线程间通信机制


volitale和synchronized

volitale变量本身就具有一种通信的作用,告诉其他线程volitale变量需要从这个主内存中获取最新的值
\基于 volatile 关键字来实现线程间相互通信是使用共享内存的思想,大致意思就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。这也是最简单的一种实现方式

等待通知机制

该范式分为两部分,分别针对等待方(消费方)和通知方(生产者)

等待方遵循如下原则:

  • 获取对象的锁
  • 如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件(while循环,防止造成虚假唤醒)
  • 条件满足则执行对应的逻辑
synchronized(对象){
	while(条件不满足){
	对象.wait();
}
对应的处理逻辑;
}

通知方遵循如下原则:

  • 获取对象的锁
  • 改变条件
  • 通知所有登台在对象上的线程

synchronized+object方式



package Multithread.Improve.consumer;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/5/4 0004  13:08
 * 线程之间的通信问题  生产者和消费者问题
 * 线程之间的通信问题,A b操作同一个变量  num=0
 * A num+1
 * B num-1
 */
public class A {

    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{for(int i=0;i<50;i++)data.decrement(); },"A").start();
        new Thread(()->{for(int i=0;i<50;i++)data.increment(); },"B").start();
        new Thread(()->{for(int i=0;i<50;i++)data.decrement(); },"C").start();
        new Thread(()->{for(int i=0;i<50;i++)data.increment(); },"D").start();

    }




}

//生产者消费者口诀:
//判断 等待、业务、通知
class Data{//资源类独立耦合

    private int number = 0;

    //+1:只要是并发编程一定要有锁
    public synchronized void increment(){

        //number=1当前线程阻塞
        //用if判断会存在问题
        //多个线程的存在可能会产生虚假唤醒的问题:将if------>while即可
        //虚假唤醒就是当一个条件满足时,很多线程都被唤醒,当时只有其中部分是有用的唤醒,其他的唤醒都是无效的
        while(number==1){
            //等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"当前number值为"+number);
        this.notifyAll();

    }


    //减法
    public synchronized  void decrement(){
        //等待
        while (number==0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        number--;
        System.out.println(Thread.currentThread().getName()+"当前number值为"+number);
        this.notifyAll();
    }

}

reentanLock+condition方式

package Multithread.Improve.consumer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* @Author Zhou  jian
* @Date 2020 ${month}  2020/5/4 0004  13:24
* 思考虚假唤醒的问题???????
* Condition的优势是哪里???????????
* 任何新技术,绝不对是覆盖原来的
* 问题:现在各个线层的执行顺序 不确定
* 如何实现有序的执行
*/
public class B {
   public static void main(String[] args) {
        Num data = new Num();
       new Thread(()->{for(int i=0;i<50;i++)data.decrement(); },"A").start();
       new Thread(()->{for(int i=0;i<50;i++)data.increment(); },"B").start();
       new Thread(()->{for(int i=0;i<50;i++)data.decrement(); },"C").start();
       new Thread(()->{for(int i=0;i<50;i++)data.increment(); },"D").start();

   }
}
class Num{

   private  int number = 0;
   //Lock锁-----》synchronized
   Lock lock = new ReentrantLock();
   //等待条件------>object notify
   Condition condition = lock.newCondition();

   //加法
   public void increment(){
       try {
           lock.lock();
           while(number==1){
               try {
                   condition.await();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
           number++;
           System.out.println(Thread.currentThread().getName()+"的值为"+number);
           condition.signalAll();
       }finally {
           lock.unlock();
       }

   }

   //减法
   public void decrement(){
       try {
           lock.lock();
           while(number==0){
               try {
                   condition.await();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
           number--;
           System.out.println(Thread.currentThread().getName()+"的值为"+number);
           condition.signalAll();
       }finally {
           lock.unlock();
       }

   }

}


Condition这种方式可以实现精确的通信与唤醒(根据某个具体的条件
而Object只能随机一个阻塞的线程或者所有阻塞的线程
下面演示 A---->B---->C----->A三个任务一次执行


package Multithread.Improve.consumer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/5/4 0004  17:38
 * 生产线:
 *    下单-----》支付-----》交易-----》物流
 *    生产者消费者  精准唤醒
 */
public class C {

    public static void main(String[] args) {
        Data3 data3 = new Data3();

        new Thread(()->{while(true) data3.printA();},"A").start();
        new Thread(()->{while(true) data3.printB();},"B").start();
        new Thread(()->{while(true) data3.printC();},"C").start();
    }





}

class Data3{//资源类lock

    Lock lock = new ReentrantLock();

    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();

    private int num = 1;//num为1的时候A执行 num为2的时候b执行

    public void printA(){
        lock.lock();
        try{
            while (num!=1){
                try {
                    condition1.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"正在执行");
            num=2;
            //唤醒指定的人(精准唤醒)
            condition2.signal();
        }finally {
            lock.unlock();
        }


    }

    public void printB(){
        lock.lock();
        try{
           while (num!=2){
                try {
                    condition2.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"正在执行");
            num=3;
            condition3.signal();

        }finally {
            lock.unlock();
        }


    }


    public void printC(){
        lock.lock();
        try{
            while (num!=3){
                try {
                    condition3.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"正在执行");
            num=1;
            condition1.signal();

        }finally {
            lock.unlock();
        }


    }






}


ThreadJoin

当调用threadJoin的这个线程执行完,主线程才能接着执行;
比如:A b c三个线程,怎么保证 A执行完 B执行完 C再执行

假如在main线程中调用thread.join方法,则main线程会等待thread线程执行完毕或者等待一定的时间。详细地,如果调用的是无参join方法,则等待thread执行完毕;如果调用的是指定了时间参数的join方法,则等待一定的时间。join()方法有三个重载版本:

public final synchronized void join(long millis) throws InterruptedException {...}
public final synchronized void join(long millis, int nanos) throws InterruptedException {...}
public final void join() throws InterruptedException {...}

以 join(long millis) 方法为例,其内部调用了Object的wait()方法,如下图:
            
在这里插入图片描述
根据以上源代码可以看出,join()方法是通过wait()方法 (Object 提供的方法) 实现的。当 millis == 0 时,会进入 while(isAlive()) 循环,并且只要子线程是活的,宿主线程就不停的等待。 wait(0) 的作用是让当前线程(宿主线程)等待,而这里的当前线程是指 Thread.currentThread() 所返回的线程。所以,虽然是子线程对象(锁)调用wait()方法,但是阻塞的是宿主线程。

ThreadLocal机制

管道输入/输出流 PipedWriter/PipedReader

在这里插入图片描述
在这里插入图片描述

CountDownLatch(为1)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值