多线程使用基础

在一个进程中,线程是独立运行的处理单元,一个进程可以拥有多个线程,CPU为每个线程分配不同时间片用来运行程序,宏观上实现多个线程并发运行的效果。
Java中使用线程通常有四种方法
1.继承Thread类
2.实现Runable接口
3.实现Callable接口
4.使用线程池

1.继承Thread类

public class MyThread extends Thread {  
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
}  
 
MyThread myThread1 = new MyThread();  
MyThread myThread2 = new MyThread();  
myThread1.start();  
myThread2.start();

继承Thread类,然后重写run()方法实现程序逻辑,其中run()方法运行在子线程中。通过实例对象 myThread的start()方法开启线程。

2.实现Runable接口

   Thread mThread=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.print("other thread");
            }
        });
        mThread.start();

在创建线程对象时传入一个Runable对象,Runnable是一个接口,实现Runable接口的run()方法来处理线程运行逻辑。run()方法的返回值为void,线程运行没有返回值。

3.实现Callable接口

Callable接口的call()方法同样用来编写线程运行逻辑,与run()方法相比多个返回值。因此可以在程序运行完返回数据。Callable接口需要与Future接口联合使用,Callable用来运行线程程序,Future用来管理线程,拿到线程返回结果。
RunnableFuture继承自Runnable,Future接口,FutureTask是实现RunnableFuture接口的类,可以通过FutureTask与Callable联合实现有返回值的线程。

 Callable<Integer> mCallable=new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return 0;
            }
        };
        FutureTask<Integer> mFutureTask=new FutureTask<>(mCallable);
        Thread mThread=new Thread(mFutureTask);
        mThread.start();

        try {
            System.out.print(mFutureTask.get()+"");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

首先实现Callable接口,然后创建FutureTask<V>对象,构造函数中传入Callable对象,之后将这个futuretask对象作为参数创建Thread对象,通过start()方法开启线程,则子线程开始运行,通过futuretask的get()方法可以拿到线程执行call()的返回值。

4使用线程池

Executors提供四种线程池,通过方法:
1.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

也可以通过重写ThreadPoolExecutor来自定义线程池。

5线程状态

1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。


线程状态.jpg

Object类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll(),唤醒在此对象监视器上等待的所有线程。

每个线程都有自己的优先级,java线程的优先级取值范围1~10,优先级高的的线程并不一定会比优先级低的线程先执行,只是获得CPU时间片的概率更大些。

6.线程常用方法

sleep(long time) 持锁休眠一段时间。
wait() 放弃锁等待一段时间,直到设置的时间结束或者对象调用notify()或者notifyAll()唤醒该线程,然后重新竞争锁。
yield() 放弃当前执行机会,与其他线程竞争时间片,如果该线程竞争成功则继续执行,否则其他线程优先执行。
join() 当一个线程在另一个线程中执行该方法时,另一个线程阻塞,等待该线程执行完后继续执行。
setPriority()更改线程优先级
interrupt():不要以为它是中断某个线程!它只是线线程发送一个中断信号,让线程在无限等待时(如死锁时)能抛出抛出,从而结束线程,但是如果你吃掉了这个异常,那么这个线程还是不会中断的!

7.线程同步

当多个线程访问主内存中同一数据时会涉及到同步问题,Java的内存模型分为主内与工作内存,每个线程直接与工作内存进行交互,工作内存与主内存进行交互。为了保证多个线程读写数据的一致性,需要加锁。通常通过synchronized来进行加锁,通过synchronized()内传入的是普通对象或者类对象,分为对象锁与类锁两种。前者针对类中普通成员有效,后者针对类中静态成员。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    小徐andorid阅读 2,797评论 3 53
  • 该文章转自:http://blog.csdn.net/evankaka/article/details/44153...
    加来依蓝阅读 7,331评论 3 87
  • 读书不要贪多,而需多加思索,这样的读书使我获益。这句话是法国卢梭,我还知道与它意思相近的故事。 从前,有一座在半山...
    王新琦阅读 577评论 0 0
  • 本文经作者授权发布 你身边是不是经常有人说这样的话“哎~我这个暴脾气!”?或者你就是这样的人,一点就爆的脾气,动不...
    小解解阅读 597评论 0 0
  • 添加映射表: netshinterfaceportproxyaddv4tov4listenport= (监听端口)...
    小黑泡泡阅读 543评论 0 0