Java学习笔记——并发编程(三)

一、wait和notify

wait和notify原理

Java学习笔记——并发编程(三)_第1张图片

  • Owner线程发现条件不满足,调用wait方法,即可进入WaitSet变为WAITING状态
  • BLOCKED和WAITING的线程都处于阻塞状态,不占用CPU时间片
  • BLOCKED线程会在Owner线程释放锁时唤醒
  • WAITING线程会在Owner线程调用notify或notifyAll时唤醒,但唤醒后并不意味着立刻获得锁,仍需进入EntryList重新竞争

API介绍

  • obj.wait()让进入object监视器的线程到waitSet等待
  • obj.notify()在object上正在waitSet等待的线程中 挑一个唤醒
  • obj.notifyAll()让object上正在waitSet等待的对象全部唤醒

它们都是线程之间协作的手段,都属于Object对象的方法。必须获得此对象的锁,才能调用这几个方法。

final static Object obj = new Object();

public static void main(String[] args){
   
	new Thread(()->{
   
		synchronized(obj){
   
			log.debug("执行....");
			try{
   
				obj.wait();  //让线程在obj上一直等待下去
			}catch(InterruptedException e){
   
				e.printStackTrace();
			}
			log.debug("其他代码....");
		}
	},"t1").start();
	
	new Thread(()->{
   
		synchronized(obj){
   
			log.debug("执行....");
			try{
   
				obj.wait();  //让线程在obj上一直等待下去
			}catch(InterruptedException e){
   
				e.printStackTrace();
			}
			log.debug("其他代码....");
		}
	},"t2").start();
	sleep(2);
	log.debug("唤醒obj上其他线程");
	synchronized(obj){
   
		obj.notify();  //唤醒obj上一个线程
		//obj.notifyAll(); //唤醒obj上所有等待线程
	}
}

notify的一种结果

20:00:53.096 [Thread-0] c.TestWaitNotify - 执行…
20:00:53.099 [Thread-1] c.TestWaitNotify - 执行…
20:00:55.096 [main] c.TestWaitNotify - 唤醒obj上其他线程
20:00:55.096 [Thread-0] c.TestWaitNotify - 其他代码…

notifyAll的结果

19:58:15.457 [Thread-0] c.TestWaitNotify - 执行…
19:58:15.460 [Thread-1] c.TestWaitNotify - 执行…
19:58:17.456 [main] c.TestWaitNotify - 唤醒obj上其他线程
19:58:17.456 [Thread-1] c.TestWaitNotify - 其他代码…
19:58:17.456 [Thread-0] c.TestWaitNotify - 其他代码…

      wait()方法会释放对象的锁,进入WaitSet等待区,从而让其他线程有机会获取对象的锁。无限制等待,直到notify为止;wait(long n)有时限的等待,到n毫秒后结束等待,或是被notify。

sleep(long n)和wait(long n)的区别
1)sleep是Thread方法,而wait是Object方法
2)sleep不需要强制和synchronized配合使用,但wait需要和synchronized一起用
3)sleep在睡眠的同时,不会释放对象锁,但wait在等待的时候会释放对象锁

      下述代码中有一个"小南"线程,五个"其他人"线程,一个"送烟的"线程。在没有烟时,小南使用sleep,不会释放room,也就是这个时候,其他人不会开始工作。

static final Obejct room = new Object();
static boolean hasCigarette = false; //有没有烟
static boolean hasTakeout = false;   //有没有外卖

public static void main(String[] args){
   
	new Thread(()->{
   
		synchronized(room){
   
			log.debug("有烟没?[{}]",hasCigarette);
			if(!hasCigarette){
   
				log.debug("没烟,先歇会!");
				sleep(2);
			}
			log.debug("有烟没?[{}]",hasCigarette);
			if(hasCigarette){
   
				log.debug("可以开始干活了");
			}
		}
	},"小南").start();
	for(int i = 0;i < 5;i++){
   
		new Thread(()->{
   
			synchronized(room){
   
				log.debug("可以开始干活了");
			}
		},"其他人").start();
	}
	sleep(1);
	new Thread(()->{
   
		hasCigarette = true;
		log.debug("烟到了哦!");
	},"送烟的").start();
}

输出
Java学习笔记——并发编程(三)_第2张图片
      下述代码在小南没有烟时,使用wait,此时会释放掉room的锁,其他人可以开始干活,当烟到的时候,调用room.notify(),唤醒线程(注意:此时因为“休息室”只有小南一人,所以notify唤醒的一定是小南)。

static final Obejct room = new Object();
static boolean hasCigarette = false; //有没有烟
static boolean hasTakeout = false;   //有没有外卖

public static void main(String[] args){
   
	new Thread(()->{
   
		synchronized(room){
   
			log.debug("有烟没?[{}]",hasCigarette );
			if(!hasCigarette){
   
				log.debug("没烟,先歇会!");
				try{
   
					room.wait();
				}catch(InterruptedException e){
   
					e.printStackTrace();
				}
			}
			log.debug("有烟没?[{}]",hasCigarette);
			if(hasCigarette){
   
				log.debug("可以开始干活了");
			}
		}
	},"小南").start();
	for(int i = 0;i < 5;i++){
   
		new Thread(()->{
   
			synchronized(room){
   
				log.debug("可以开始干活了");
			}
		},"其他人").start();
	}
	sleep(1);
	new Thread(()->{
   
		synchronized(room){
   
			hasCigarette = true;
			log.debug("烟到了哦!");
			room.notify();
		}
		
	},"送烟的").start();
}

输出
Java学习笔记——并发编程(三)_第3张图片

      解决了其他干活的线程阻塞的问题,但如果有其他线程也在等待条件呢(即“休息室”不止小南一人呢)?
      下述代码有一个“小南”线程,一个“小

你可能感兴趣的:(java,java)