Java 线程间通信

线程间的交互和通信

  1. 一个线程启动另一个线程

    public static void main(String[] args){
      new Thread().start();
    }
    

    主线程启动另一个线程。

  2. 一个线程终结另个一线程
    A. Thread.stop()来停止一个线程,但是已经被弃用了,因为stop结果是不可预期的,它是直接将线程干掉了,即是你的业务刚执行到一半,这样就导致结果是不可预期的,比较危险。

      Thread thread = new Thread();
      thread.start();
      thread.stop();
    

    B. Thread.interrupt()来中断一个线程的执行。它的原理是调用interrupt方法后,将该线程编辑为中断状态,需要我们自己处理这个状态。

      Thread thread = new Thread(){
          @Override
          public void run(){
              if(isInterrupted()){
                  //do something
              }
          }
      };
      thread.start();
      thread.interrupt();
    

    判断一个线程是否标记为中断状态,可以使用thread.isInterrupted(),也可以使用Thead的静态方法Thread.interruped(),二者的区别是前者可以重复多次使用,后者只能使用一次,因为使用之后会将标记复位,即置为false,实际使用根据自己具体的逻辑来具体使用哪种方式。

    C. 当一个线程正在休眠中,此时被中断,会怎样?
    答案是会立即抛出InterruptedException,然后线程会被立即结束,但是中断标志一直是false。因为当处于休眠状态,说明这个线程目前没有在处理事情,也就是说可以立即打断,也不会产生影响,所以会被立即终止。这也是当我们写Thread.sleep(10); 的时候要求强制捕获InterruptedException的原因,所以如果我们有需要则要在异常中处理中断的后续逻辑。

  3. 两个线程互相配合
    需要使用wait()notify()以及notifyAll(),这里有必要说明下,这3个方法是针对monitor来说的,并不是针对线程,需要等的是monitor,需要唤醒的也是monitor,和线程无关,而且这3个方法也必须是在同步代码块中才可以使用。
    下面我们来简单说一下waitnotify的工作模型。

    工作模型

首先我们看下这段代码,有两个同步方法methodAmethodB,他们的锁对象都是this,即monitor是同一个,下面来说明下这个工作模型。

ThreadA先访问methodB时,它先来到等待访问排队区,发现里面没人,就他自己,于是它从monitor那里拿到了锁,此时的线程正在访问区里面放的是ThreadA。但是methodB里面的代码是wait(),此时monitor会将ThreadA放到右面的等待唤醒区,同时ThreadA所持有的锁也会被释放,正在访问区是空的。这时ThreadB来了,想访问methodA,它问了下monitor,我可以访问methodA吗,因为此时的ThreadA的锁已经释放了,它理所当然的可以访问methodA,此时的线程正在访问区中里面放的是ThreadB, ThreadB拿着锁来到了methodA内部,此时它发现里面是notifyAll,所以此时的monitor就将等待唤醒区里面的所有等待唤醒的线程都唤醒了,然后ThreadB就是放了锁,然后骂骂咧咧的走了,此时线程正在访问区是空的。等待唤醒区中的ThreadA被唤醒,他只能再次来到等待访问排队区,不能插队到正在访问区中,只能公平的再次去竞争锁,然后发下排队的就他自己,于是它又从monitor那里拿到了锁,然后就去访问methodB了,但是里面又是wait(),于是乎它又释放锁,然后又进入了等待唤醒区,可以没有人再去访问methodA来告诉monitor区唤醒唤醒等待区里面的线程了,此时ThreadA将永远在等待唤醒区等一辈子。

大致的一个工作模型就是这样的,可能描述的不太清楚,但是大致原理是清晰的,相信多看几遍总会明白的,哈哈哈。。。

这里为什么调用的是nitofyAll呢,而不是notify呢?因为针对这个monitor而言,有可能等待唤醒区有好多个线程正在等待,而不是一个,如果只唤醒一个,那剩下的咋办?所以只能一次性唤醒所有的,除非你明确知道等待唤醒区中只有一个线程在等待被唤醒。
所以从这个工作模型来看,waitnotify 以及notifyAll 都是针对monitor而言的,是monitor让一个线程区等待唤醒区,也是monitor来进行唤醒等待唤醒区里面的线程,而且waitnotify一定是成对出现的。
下面举一个简单的栗子。

 public class Demo {

 public static void main(String[] args) {
     new WaitNotifyTest().runTest();
 }

 private static class WaitNotifyTest{

     private int x;

     void runTest() {
         Thread threadA = new Thread(){
             @Override
             public void run() {
                 try {
                     Thread.sleep(2000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 plus();
             }
         };
         threadA.start();
         Thread threadB = new Thread(){
             @Override
             public void run() {
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 printX();
             }
         };
         threadB.start();
     }

     private synchronized void plus() {
         x++;
         notifyAll();
     }

     private synchronized void printX() {
         if (x == 0) {
             try {
                 wait();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         System.out.println("The x is: " + x);
     }

 }
}

执行结果如下:


结果
  1. 插队
    将一个线程插到当前线程之前执行,插队的方法就是join
    简单代码如下:
    public static void main(String[] args) {
        Thread threadA = new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("run method in ThreadA class is finished。");
            }
        };
        threadA.start();
        try {
            threadA.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main method is finished。");
    }
    

    上述代码执行的结果:


    执行结果

ThreadA执行了join插队方法后,main方法所在的线程会等ThradA线程执行结果后在执行。
join可以说是简化后的wait,notify,只是不需要我们调用notify

它的作用时将并行的两个线程变成串行化。

  1. yield。暂时让出时间片,让给同优先级的线程,这个时间很短很短,让出之后马上会再次获取到时间片。

由于个人能力有限,如有错误之处,还望指出,我会第一时间验证并修改。
理解事物,看本质。共勉。

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

推荐阅读更多精彩内容

  • 摘自《Java并发编程的艺术》 1 volatile和synchronized关键字 关键字volatile可以用...
    沉沦2014阅读 531评论 0 2
  • 现在计算机和智能手机都是多核处理器,为了更好地发挥设备的性能,提高应用程序的体验性,多线程是必不可少的技术。线程之...
    落英坠露阅读 2,449评论 0 4
  • 线程间的通信 线程间通信:多个线程在处理同一资源,但是任务却不同 1 多线程执行同一资源: 2 多线程执行同一资源...
    柳子陌阅读 248评论 0 1
  • 一,介绍 本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信,故摘抄...
    那些年的代码阅读 162评论 0 0
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,519评论 28 53