文章目录
![](https://img-blog.csdnimg.cn/20200603192307113.png)
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