美文网首页
Java 线程间通信

Java 线程间通信

作者: 一心729 | 来源:发表于2021-05-10 23:09 被阅读0次

线程间的交互和通信

  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。暂时让出时间片,让给同优先级的线程,这个时间很短很短,让出之后马上会再次获取到时间片。

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

相关文章

  • 线程间通信剖析——Java进阶

    Java线程间通信剖析 本文将介绍常用的线程间通信工具CountDownLatch、CyclicBarrier和P...

  • 2.Java内存模型

    1.java并发编程的线程间通信及线程间如何同步线程间通信分为:共享内存,消息传递。线程间同步:共享内存是代码指定...

  • Java多线程(2)

    Java多线程(2) 线程间的通信 线程间的通信又称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号或等...

  • Java - 线程间通信

    涉及到的知识点:thread.join(), object.wait(), object.notify(), Co...

  • Java线程间通信

    涉及到多个线程协同完成某个任务的时候,就用到了线程间通信的相关知识点。这其中涉及到的知识点有:(1)thread....

  • Java 线程间通信

    线程间的交互和通信 一个线程启动另一个线程public static void main(String[] arg...

  • Java 线程间通信

    1. 线程之间如何通信 共享内存(隐式通信) 消息传递(显式通信 wait / notify synchroniz...

  • Java线程<第四篇>:线程间通信

    线程间通信是Java线程必须掌握的课程之一。线程间的通信的前提是,必须要保证线程还活着,可以使用阻塞方法,将线程暂...

  • Java多线程:线程间通信之volatile与sychroniz

    由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信。 ...

  • Java线程简介

    本文将介绍Java线程的状态、线程的中断、线程间通信和线程的实现。 线程的状态 Java语言定义了6种不同的线程状...

网友评论

      本文标题:Java 线程间通信

      本文链接:https://www.haomeiwen.com/subject/jdovdltx.html