实现线程的方式,源码分析:Runnable, Thread, Callable, Future, FutureTask

前言

在 Java 中,实现线程的方式主要有以下几种方式:继承 Thread, 实现 Runnable 和实现 Callable 这三种方式;采用哪种方式,主要根据实际情况而定,比如:因为 Java 是单继承,所以如果定义的线程还有其他父类的话,就可以使用实现 Runnable 的方式,如果定义的线程就只有 Thread 一个父类,就可以从用继承 Thread 的方式来声明线程;如果线程执行后需要有返回值,则可以采用实现 Callable 的方式来声明线程。

Runnable

Runnable 的源码如下:

Runnable 它是一个接口,只有一个 run 方法,当线程在执行的时候,会自动的执行该 run 方法,我们采用实现 Runnable 的方式声明线程的时候,就需要重写该 run 方法;该方式需要使用 Thread 类的 start 方法来启动线程。如下所示:

Thread

Thread 类本身就是一个线程,它实现了 Runnable 接口,它提供了很多的方法来控制线程的行为,类图如下:

每个线程都有优先级(priority),高优先级的线程会优于低优先级的线程执行,但并不是说高优先级的线程一定在低优先级的线程之前执行,只是获取到 CPU 的概率要大些。线程的优先级共有 10 个级别,最低级别为1,默认的级别为5,最高级别为10。

当Java虚拟机启动时,通常会有一个非守护程序线程(通常调用某个指定类的main方法)。 当在遇到如下任意情况之前,Java虚拟机会继续执行线程:

1. 调用 Runtime 类的 exit 方法,并且安全管理器允许执行退出操作

2. 所有非守护线程都已“死亡”

3. run 方法执行完毕

4. run 方法抛出异常。

下面来看下 Thread 类的源码,只会选一些常见的进行分析:

下面是 Thread 的一些常见方法:

yield()

yield 方法会告诉线程调度器,当前线程愿意放弃CPU的使用权,把CPU让给其他线程执行,当前线程会从执行状态变为可执行状态;但是,调度器可能会忽略该消息,也就是说,yield 方法有意愿放弃CPU的使用权,但是还得看调度器是否同意,即使 yield 已经成功的放弃了CPU的使用权,但是在下一轮调度的时候,还是会调度到它,让它继续执行;yield 方法主要是用来保证其他线程有机会执行而不至于会导致饥饿。一般很少使用该方法,但是它对于调试和测试可能很有用。

测试:

sleep() 

sleep 方法导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数, 该线程不会释放已经拥有的锁。 如果其他的线程中断了一个休眠的线程,sleep方法会抛出Interrupted Exception。

start()

start 方法是用来启动一个线程,当调用 start 方法后,JVM 会自动去执行当前线程的 run 方法,从上述源码中可以看到,start 会执行 start0 方法,而 start0 方法是一个本地方法,run 方法应该在里面调用的吧。

start 方法只能调用一次,多次调用会出错。

interrupt()

interrupt 方法中断当前线程。如果在调用 wait 或 join 时阻塞了这个线程,那么它的中断状态将被清除,它将收到一个 InterruptedException。如果此线程在I / O操作中被阻塞,那么通道将关闭,线程的中断状态将被设置,并且线程将接收到 ClosedByInterruptExcetion。如果上述操作没有抛出异常,则将设置该线程的中断状态。

interrupt方法并不是强制终止线程,它只能设置线程的中断状态

interrupted()

测试当前线程是否已经中断。线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态)

isInterrupted()

测试线程是否已经中断。线程的中断状态不受该方法的影响。

join()

join 方法把指定线程加入到当前线程中执行,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

以上就是 Thread 类中的常见方法。

既然说到 sleep 方法,就会想到 Object 的 wait 方法。wait 方法也会是线程暂停执行,直到由 notify 或 notifyAll 进行唤醒。调用 wait 方法后,线程会释放掉锁。

Callable

Callable 也可以用来实现线程,采用 Callable 方式执行线程,我们可以得到线程的一个执行结果,线程的执行结果通过 Future 进行返回;

Callable 和 Runnable  类似,都是为了线程而设计,但是 Runnable 的 run 方法执行线程后不能返回结果,也不能抛出异常;而 Callable 的 call 方法可以有返回值和抛出异常。

先看下它的源码实现:

Callable 需要配合 ExecutorService 来进行使用,它提供了一系列的的 submit 来执行:

 Future

一个 Future 代表着一个异步计算结果,它提供了一些方法去检查计算是否完成,等待其完成,以及检索计算结果等。接下来看下它的接口声明:

看下它的一个使用:

FutureTask

FutureTask 提供了 Future 类的一个基本实现,它的类图如下:

可以看到,FutureTask 还实现了 Runnable 接口,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

以上就是实现线程的几种方式。

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

推荐阅读更多精彩内容

  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    胜浩_ae28阅读 5,033评论 0 23
  •   一个任务通常就是一个程序,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含了多个顺序执行流,每个顺...
    OmaiMoon阅读 1,629评论 0 12
  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    小徐andorid阅读 2,781评论 3 53
  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 11,147评论 4 56
  • 喜欢这样的天气,丝丝凉意,好像要下雨,好像又不下雨,轻快的南山南的旋律,希望每一天的生活都可如此美好
    DISPARIY阅读 229评论 0 0