/**
* 线程之间的通信问题:生成者和消费者问题 等待唤醒,通知唤醒
* 线程交替执行 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 <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//等待,业务,通知
class Data{//数字 资源
private int number=0;
//+1
public synchronized void increment() throws InterruptedException {
if (number!=0) {//防止虚假换醒使用while就可以解决
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程 +1 完毕了
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
if (number==0) {
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程 -1 完毕了
this.notifyAll();
}
}
这里使用了wait方法,也就是等待的意思,首先要弄懂什么是wait,wait和sleep之间的区别是什么,wait它是来自Object类,sleep它是来自Thread,wait会释放锁,sleep不会释放锁,wait必须在同步代码块中,sleep可以在任何地方休眠
如果使用if来进行,线程等待判断的话,会出现一个问题,也就是虚假唤醒,如果出现了这类问题的解决办法就是将if改为while进行判断,代码如下:
/**
* 线程之间的通信问题:生成者和消费者问题 等待唤醒,通知唤醒
* 线程交替执行 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 <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//等待,业务,通知
class Data{//数字 资源
private int number=0;
//+1
public synchronized void increment() throws InterruptedException {
while (number!=0) {//防止虚假换醒使用while就可以解决
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程 +1 完毕了
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while (number==0) {
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程 -1 完毕了
this.notifyAll();
}
}
下面再来看看lock版的生成消费者和消费者
/**
* 线程之间的通信问题:生成者和消费者问题 等待唤醒,通知唤醒
* 线程交替执行 A B 操作同一个变量 num=0
* A num+1
* B num-1
*/
public class B {
public static void main(String[] args) {
Data data =new Data();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//等待,业务,通知
class Data2{//数字 资源
private int number=0;
Lock lock =new ReentrantLock();
Condition condition = lock.newCondition();
// condition.await();//等待
// condition.signalAll();//唤醒全部
//+1
public synchronized void increment() throws InterruptedException {
lock.lock();
try {
while (number!=0) {//防止虚假换醒使用while就可以解决
//等待
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程 +1 完毕了
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public synchronized void decrement() throws InterruptedException {
lock.lock();
try {
if (number==0) {
//等待
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程 -1 完毕了
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
在使用lock锁的时候,切记需要使用finally关闭锁,不然会出现死锁问题
如果需要指定下一个线程进行顺序,需要怎么办呢,那可以使用Condition来指定通知线程,它可以精准通知和唤醒线程
public class C {
public static void main(String[] args) {
Data3 data =new Data3();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printC();
}
},"C").start();
}
}
// 资源类 属性+方法
/**
* A 执行完调用B,B执行完调用C,C执行完调用A
*/
class Data3{
private Lock lock=new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number=1;//1A 2B 3C
public void printA(){
lock.lock();
try {
//业务 判断 执行 通知
while (number!=1){
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAAAAAAA");
//唤醒指定的人 B
number=2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try { //判断 执行 通知
while (number!=2){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>BBBBBBB");
//唤醒指定的人 C
number=3;
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {//判断 执行 通知
while (number!=3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>CCCCCCC");
//唤醒等待的人 A
number=1;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}