我们多个线程之间通信,有wait() notify(),notifyall()方法,但是wait()方法是在哪里睡,之后被唤醒的时候就在哪里醒来,所以我们的wait()方法是不能在if里面,使用while,当唤醒的时候,会重新判断条件,if是不会判断的;
wait(),notifyAll(),notify()
//第一步 创建资源类,定义属性和操作方法
class Share {
//初始值
private int num = 0;
//+1的方法
public synchronized void incr() throws InterruptedException {
//第二步 判断 干活 通知
if(number != 0) { //判断number值是否是0,如果不是0,等待
this.wait(); //在哪里睡,就在哪里醒
}
//如果number值是0,就+1操作
number++;
System.out.println(Thread.currentThread().getName()+" :: "+num);
//通知其他线程
this.notifyAll(); //注意这里的通知是随机的,就是只能通知全部
}
//-1的方法
public synchronized void decr() throws InterruptedException {
//判断
if(number != 1) {
this.wait();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+" :: "+number);
//通知其他线程
this.notifyAll();
}
}
public class ThreadDemo1 {
//第三步 创建多个线程,调用资源类的操作方法
public static void main(String[] args) {
Share share = new Share();
//创建线程
new Thread(()->{
for (int i = 1; i <=10; i++) {
try {
share.incr(); //+1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for (int i = 1; i <=10; i++) {
try {
share.decr(); //-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
}
}
private Lock lock= new ReentrantLock(); //创建可重锁
private Condition condition= lock.newCondition();
//他能操作的对象
class LShare{
//这是共享资源,注意锁的创建和使用,其他的和上面基本相同
private int num=0;
private Lock lock= new ReentrantLock(); //创建可重锁
private Condition condition= lock.newCondition();
//创建操作的方法
public void add (){
lock.lock(); //首先 手动上锁;
try { //判断,干活,通知
while (num!=0){
condition.await();
//它使用的是这个对象 调用方法 等待
}
num++;
System.out.println( Thread.currentThread().getName()+" 干活完成 :"+num);
condition.signalAll(); //这个通知方法
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //最终不管出现什么错误,都会解锁
}
}
/**定制化通信 ( 规定完成工作量,交替)
* AA 打印 5 次 , BB打印10次 CC打印15次
* 完成10次这样的交替
* 怎么完成呢? 设置标志位,对应线程, 指定唤醒线程
* sysnchronzied 是随机唤醒的, Lock 锁创建Condition 可以指定唤醒
*/
class ShareRes{
private int flag =1; // 1 AA, 2 BB ,3 CC
Lock lock = new ReentrantLock(); //一定记得创建可重锁
Condition c1 =lock.newCondition(); //可以指定唤醒线程
Condition c2 =lock.newCondition();
Condition c3 =lock.newCondition();
//注意唤醒的线程,以及标志位, 和线程的start
//指定AA 做的工作 参数:循环次数
public void AA(int loop) throws InterruptedException {
//上锁 ,判断 ,干活,通知,解锁
lock.lock();
try {
while (flag != 1) {
c1.await();
}
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " ::" + i + "循环的次数" + loop);
}
flag = 2; //修改标志位,定向唤醒 线程b
c2.signal();
}finally {
lock.unlock();
}
}
//指定AA 做的工作 参数:循环次数
public void BB(int loop) throws InterruptedException {
//上锁 ,判断 ,干活,通知,解锁
lock.lock();
try {
while (flag != 2) {
c2.await();
}
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + " ::" + i + "循环的次数" + loop);
}
flag = 3; //修改标志位,定向唤醒 线程b
c3.signal();
}finally {
lock.unlock();
}
}
//指定AA 做的工作 参数:循环次数
public void CC(int loop) throws InterruptedException {
//上锁 ,判断 ,干活,通知,解锁
lock.lock();
try {
while (flag != 3) {
c3.await();
}
for (int i = 1; i <= 15; i++) {
System.out.println(Thread.currentThread().getName() + " ::" + i + "循环的次数" + loop);
}
flag = 1; //修改标志位,定向唤醒 线程A
c1.signal();
}finally {
lock.unlock();
}
}
}
public class c01 {
public static void main(String[] args) {
ShareRes shareRes = new ShareRes();
new Thread( //创建三个线程
() ->{
for (int i = 0; i < 10; i++) {
try {
shareRes.AA(i);
} catch (InterruptedException e) {
e.printStackTrace();
} } }
,"AA" ).start();
new Thread(
() ->{
for (int i = 0; i < 10; i++) {
try {
shareRes.BB(i);
} catch (InterruptedException e) {
e.printStackTrace();
} } }
,"BB" ).start();
new Thread(
() ->{
for (int i = 0; i < 10; i++) {
try {
shareRes.CC(i);
} catch (InterruptedException e) {
e.printStackTrace();
} } }
,"CC" ).start();
}
}