Java并发07:Thread的基本方法(4)-Thread.sleep()、Object.wait()、notify()和notifyAll()
2018-03-12 15:08
781 查看
[超级链接:Java并发学习系列-绪论]
本章主要对Java中Thread类的基本方法进行学习。
Thread.sleep(long):强制线程睡眠一段时间。
Thread.activeCount():获取当前程序中存活的线程数。
thread.start():启动一个线程。
Thread.currentThread():获取当前正在运行的线程。
thread.getThreadGroup():获取线程所在线程组。
thread.getName():获取线程的名字。
thread.getPriority():获取线程的优先级。
thread.setName(name):设置线程的名字。
thread.setPriority(priority):设置线程的优先级。
thread.isAlive():判断线程是否还存活着。
thread.isDaemon():判断线程是否是守护线程。
thread.setDaemon(true):将指定线程设置为守护线程。
thread.join():在当前线程中加入指定线程,使得这个指定线程等待当前线程,并在当前线程结束前结束。
thread.yield():使得当前线程退让出CPU资源,把CPU调度机会分配给同样线程优先级的线程。
thread.interrupt():使得指定线程中断阻塞状态,并将阻塞标志位置为true。
object.wai()、object.notify()、object.notifyAll():Object类提供的线程等待和线程唤醒方法。
为了便于阅读,将以上所有方法,放在5篇文章中进行学习。
本章主要学习绿色字体标记的方法,其他方法请参加其他章节。
说明:
sleep():属于Thread类的方法。
sleep():让当前正在运行的线程休眠指定毫秒的时间。
sleep():休眠的线程并不会失去任何的监视器(可以理解为成锁)。
再来看看wait()方法的定义与注释:
说明:
wait():wait()是Object的方法。
wait():让当前线程等待,直到另一个线程调用了当前对象上的notify()或者notifyAll()方法。
wait():在调用时,会释放当前对象的监视器的所有权(可以理解成解锁)。
调用wait()类的线程必须拥有这个对象的监视器(可以理解成锁)。
wait()的线程会一直等待,直到另一线程通知当前对象上的所有线程通过notify()唤醒单个线程或者通过notifyAll()唤醒全部线程。
wait()也可以只等待一定的时间就自动唤醒,方法是wait(long)。
sleep()与wait()的区别和联系:
二者都是让线程暂停运行。
sleep()不会释放任何锁,wait()会释放对象上的锁。
sleep()正常恢复的方式只能是等待时间耗尽,wait()除了等待时间耗尽,还可以被其他线程唤醒(notify()和notifyAll)。
说明:
notify():唤醒等待对象监视器的单个线程。
notify():如果等待对象监视器的有多个线程,则选取其中一个线程进行唤醒。
notify():选择唤醒哪个线程是任意的,由CPU自己决定。
再来看看这Object.notifyAll()的定义和注释:
说明:
notifyAll():唤醒等待对象监视器的所有线程。
很显然,notify和notifyAll一个是唤醒单个线程,一个是唤醒所有线程,前提是都在指定的对象监视器上。
程序中有两个类:厨房类和餐厅类。厨房负责炒菜(生产者),餐厅负责卖菜(消费者)。
厨房中只有一个厨子,他炒好一道菜之后,需要休息2秒钟。
厨房中有菜架子,能够存放炒好的菜,作为储备,以应对生意火爆的饭点时间。
菜架子上最多盛放6个盘子。所以,当菜架子上盛满6道菜之后,厨师就可以暂时休息了。
餐厅负责卖菜,大概需要花费1.5秒到2.5秒才能卖出一道菜。
餐厅会时刻查看菜架子上的菜品数量,当储备的菜品少于2盘时,就通知厨师该继续炒菜了,以免出现供不应求的情况。
在饭点时间,虽然厨师一直在炒菜,也可能因为卖菜卖的太快,导致菜架子上一盘菜都没有,这时餐厅只能耐心等待厨师炒菜。
wait()以及notify()方法都需要锁定共同的对象,在这个场景中,这个共同的对象就是:菜架子(厨房通过菜架子盛放菜品,餐厅从菜架子获取菜品)。
当菜架子上盛满6道菜之后,厨师就可以暂时休息了—-这就是调用wait()的时机。
当储备的菜品少于2盘时,就通知厨师该继续炒菜了—-这就是调用notify()的时机。
将菜架子以队列Queue的形式实现,以FIFO(First in, First out,先进先出)。
代码:
本章主要对Java中Thread类的基本方法进行学习。
1.序言
Thread类作为线程的基类,提供了一系列方法,主要有:Thread.sleep(long):强制线程睡眠一段时间。
Thread.activeCount():获取当前程序中存活的线程数。
thread.start():启动一个线程。
Thread.currentThread():获取当前正在运行的线程。
thread.getThreadGroup():获取线程所在线程组。
thread.getName():获取线程的名字。
thread.getPriority():获取线程的优先级。
thread.setName(name):设置线程的名字。
thread.setPriority(priority):设置线程的优先级。
thread.isAlive():判断线程是否还存活着。
thread.isDaemon():判断线程是否是守护线程。
thread.setDaemon(true):将指定线程设置为守护线程。
thread.join():在当前线程中加入指定线程,使得这个指定线程等待当前线程,并在当前线程结束前结束。
thread.yield():使得当前线程退让出CPU资源,把CPU调度机会分配给同样线程优先级的线程。
thread.interrupt():使得指定线程中断阻塞状态,并将阻塞标志位置为true。
object.wai()、object.notify()、object.notifyAll():Object类提供的线程等待和线程唤醒方法。
为了便于阅读,将以上所有方法,放在5篇文章中进行学习。
本章主要学习绿色字体标记的方法,其他方法请参加其他章节。
2.Object.wait()与Thread.sleep()
先来看看sleep()的定义与注释:/** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the precision and accuracy of system timers and schedulers. The thread * does not lose ownership of any monitors. * ... */ public static native void sleep(long millis) throws InterruptedException;
说明:
sleep():属于Thread类的方法。
sleep():让当前正在运行的线程休眠指定毫秒的时间。
sleep():休眠的线程并不会失去任何的监视器(可以理解为成锁)。
再来看看wait()方法的定义与注释:
/** * Causes the current thread to wait until another thread invokes the * {@link java.lang.Object#notify()} method or the * {@link java.lang.Object#notifyAll()} method for this object. * In other words, this method behaves exactly as if it simply * performs the call {@code wait(0)}. * <p> * The current thread must own this object's monitor. The thread * releases ownership of this monitor and waits until another thread * notifies threads waiting on this object's monitor to wake up * either through a call to the {@code notify} method or the * {@code notifyAll} method. The thread then waits until it can * re-obtain ownership of the monitor and resumes execution. * <p> * ... */ public final void wait() throws InterruptedException { wait(0); }
说明:
wait():wait()是Object的方法。
wait():让当前线程等待,直到另一个线程调用了当前对象上的notify()或者notifyAll()方法。
wait():在调用时,会释放当前对象的监视器的所有权(可以理解成解锁)。
调用wait()类的线程必须拥有这个对象的监视器(可以理解成锁)。
wait()的线程会一直等待,直到另一线程通知当前对象上的所有线程通过notify()唤醒单个线程或者通过notifyAll()唤醒全部线程。
wait()也可以只等待一定的时间就自动唤醒,方法是wait(long)。
sleep()与wait()的区别和联系:
二者都是让线程暂停运行。
sleep()不会释放任何锁,wait()会释放对象上的锁。
sleep()正常恢复的方式只能是等待时间耗尽,wait()除了等待时间耗尽,还可以被其他线程唤醒(notify()和notifyAll)。
3.Object.notify()和Object.notifyAll()
先来看看这Object.notify()的定义和注释:/** * Wakes up a single thread that is waiting on this object's * monitor. If any threads are waiting on this object, one of them * is chosen to be awakened. The choice is arbitrary and occurs at * the discretion of the implementation. A thread waits on an object's * monitor by calling one of the {@code wait} methods. * <p> * ... */ public final native void notify();
说明:
notify():唤醒等待对象监视器的单个线程。
notify():如果等待对象监视器的有多个线程,则选取其中一个线程进行唤醒。
notify():选择唤醒哪个线程是任意的,由CPU自己决定。
再来看看这Object.notifyAll()的定义和注释:
/** * Wakes up all threads that are waiting on this object's monitor. A * thread waits on an object's monitor by calling one of the * {@code wait} methods. * <p> * ... */ public final native void notifyAll();
说明:
notifyAll():唤醒等待对象监视器的所有线程。
很显然,notify和notifyAll一个是唤醒单个线程,一个是唤醒所有线程,前提是都在指定的对象监视器上。
4.实例代码与结果
4.1.实例场景
这是一个典型的生产者与消费者的示例。程序中有两个类:厨房类和餐厅类。厨房负责炒菜(生产者),餐厅负责卖菜(消费者)。
厨房中只有一个厨子,他炒好一道菜之后,需要休息2秒钟。
厨房中有菜架子,能够存放炒好的菜,作为储备,以应对生意火爆的饭点时间。
菜架子上最多盛放6个盘子。所以,当菜架子上盛满6道菜之后,厨师就可以暂时休息了。
餐厅负责卖菜,大概需要花费1.5秒到2.5秒才能卖出一道菜。
餐厅会时刻查看菜架子上的菜品数量,当储备的菜品少于2盘时,就通知厨师该继续炒菜了,以免出现供不应求的情况。
在饭点时间,虽然厨师一直在炒菜,也可能因为卖菜卖的太快,导致菜架子上一盘菜都没有,这时餐厅只能耐心等待厨师炒菜。
4.2.实现思路
这是一个典型的线程等待与唤醒的问题。需要用到synchronized关键字、wait()以及notify()方法。wait()以及notify()方法都需要锁定共同的对象,在这个场景中,这个共同的对象就是:菜架子(厨房通过菜架子盛放菜品,餐厅从菜架子获取菜品)。
当菜架子上盛满6道菜之后,厨师就可以暂时休息了—-这就是调用wait()的时机。
当储备的菜品少于2盘时,就通知厨师该继续炒菜了—-这就是调用notify()的时机。
4.3.实例代码
关于实例代码的其他说明:将菜架子以队列Queue的形式实现,以FIFO(First in, First out,先进先出)。
代码:
/** * <p>线程基本方法(sleep、wait、notify、notifyAll、synchronized)</p> * * @author hanchao 2018/3/11 14:14 **/ public class ThreadWaitDemo { private static final Logger LOGGER = Logger.getLogger(ThreadWaitDemo.class); //现有菜品 private static Queue<String> foodQueue = (Queue<String>) new LinkedList<String>(); //厨房的菜架能够存放菜品的最大值 private static int maxSize = 6; //当厨房还剩几个菜时,继续炒菜 private static int minSize = 2; /** * <p>菜品工具类</p> * * @author hanchao 2018/3/11 15:03 **/ public static class Foods { private static String[] foods = new String[]{"[鱼香肉丝]", "[水煮肉片]", "[地三鲜]", "[红烧肉]", "[干煸豆角]"}; /** * <p>随机获取一个菜名</p> * * @author hanchao 2018/3/11 15:46 **/ public static String randomFood() { return foods[RandomUtils.nextInt(0, foods.length)]; } } /** * <p>厨房生产各种菜肴(wait、notify、synchronized)</p> * * @author hanchao 2018/3/11 14:21 **/ static class Kitchen extends Thread { @Override public void run() { while (true) { synchronized (foodQueue) {//加锁 //菜架满了,厨房不必再茶菜,等着前厅通着再炒菜 if (maxSize == foodQueue.size()) { try { LOGGER.info("厨房菜架满了,厨房不必再茶菜,等着前厅通着再炒菜,当前菜架:" + foodQueue.toString()); foodQueue.wait(111); } catch (InterruptedException e) { e.printStackTrace(); } } else { //炒一个菜 String food = Foods.randomFood(); foodQueue.add(food); try { LOGGER.info("厨房炒了一个:" + food + ",厨师歇息2分钟...当前菜架:" + foodQueue.toString()); //抄完一个菜,歇息1分钟 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } /** * <p>餐厅消费各种菜肴(wait、notify、synchronized)</p> * * @author hanchao 2018/3/11 14:54 **/ static class Restaurant extends Thread { @Override public void run() { while (true) { synchronized (foodQueue) {//加锁 //如果生意太好,菜品供不应求,只能等待厨房做菜... if (0 == foodQueue.size()) { try { LOGGER.info("餐厅:生意太好,菜品供不应求,只能等待厨房做菜...当前菜架:" + foodQueue.toString()); Thread.sleep(2500); } catch (InterruptedException e) { e.printStackTrace(); } } else if (foodQueue.size() > 0) {//如果有菜,则消费菜品 //当厨房的储备菜品所剩不多时,告诉厨师开始炒菜 if (foodQueue.size() <= minSize) { foodQueue.notify(); LOGGER.info("餐厅:厨房的储备菜品所剩不多时,厨师们该继续炒菜了..."); } //消费菜品 String food = foodQueue.poll(); try { //随机一定时间吃掉一道菜 Thread.sleep(RandomUtils.nextInt(1500, 2500)); LOGGER.info("餐厅:刚刚消费了一道" + food + "...当前菜架:" + foodQueue.toString()); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } /** * <p>线程基本方法(sleep、wait、notify、notifyAll、synchronized)</p> * * @author hanchao 2018/3/11 14:15 **/ public static void main(String[] args) throws InterruptedException { //通过关键字synchronized和Object的方法wait()/notify()/notifyAll()实现线程等待与唤醒 //通过object.wait(),使得对象线程进行入等待唤醒状态,并是否对象上的锁 //通过object.notify()/object.notifyALL(),唤醒此对象上等待的线程,并获得对象上的锁 //wait()/notify()/notifyAll()必须在synchronized中使用 new Kitchen().start(); //先让厨房多炒几个菜 Thread.sleep(10000); //餐厅开始消费 new Restaurant().start(); } }
4.4.运行结果
运行结果:2018-03-12 14:44:56 INFO ThreadWaitDemo:65 - 厨房炒了一个:[水煮肉片],厨师歇息2分钟...当前菜架:[[水煮肉片]] 2018-03-12 14:44:58 INFO ThreadWaitDemo:65 - 厨房炒了一个:[鱼香肉丝],厨师歇息2分钟...当前菜架:[[水煮肉片], [鱼香肉丝]] 2018-03-12 14:45:00 INFO ThreadWaitDemo:65 - 厨房炒了一个:[鱼香肉丝],厨师歇息2分钟...当前菜架:[[水煮肉片], [鱼香肉丝], [鱼香肉丝]] 2018-03-12 14:45:02 INFO ThreadWaitDemo:65 - 厨房炒了一个:[干煸豆角],厨师歇息2分钟...当前菜架:[[水煮肉片], [鱼香肉丝], [鱼香肉丝], [干煸豆角]] 2018-03-12 14:45:04 INFO ThreadWaitDemo:65 - 厨房炒了一个:[干煸豆角],厨师歇息2分钟...当前菜架:[[水煮肉片], [鱼香肉丝], [鱼香肉丝], [干煸豆角], [干煸豆角]] 2018-03-12 14:45:08 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[水煮肉片]...当前菜架:[[鱼香肉丝], [鱼香肉丝], [干煸豆角], [干煸豆角]] 2018-03-12 14:45:10 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[鱼香肉丝]...当前菜架:[[鱼香肉丝], [干煸豆角], [干煸豆角]] 2018-03-12 14:45:11 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[鱼香肉丝]...当前菜架:[[干煸豆角], [干煸豆角]] 2018-03-12 14:45:11 INFO ThreadWaitDemo:99 - 餐厅:厨房的储备菜品所剩不多时,厨师们该继续炒菜了... 2018-03-12 14:45:13 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[干煸豆角]...当前菜架:[[干煸豆角]] 2018-03-12 14:45:13 INFO ThreadWaitDemo:99 - 餐厅:厨房的储备菜品所剩不多时,厨师们该继续炒菜了... 2018-03-12 14:45:15 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[干煸豆角]...当前菜架:[] 2018-03-12 14:45:15 INFO ThreadWaitDemo:90 - 餐厅:生意太好,菜品供不应求,只能等待厨房做菜...当前菜架:[] 2018-03-12 14:45:17 INFO ThreadWaitDemo:65 - 厨房炒了一个:[红烧肉],厨师歇息2分钟...当前菜架:[[红烧肉]] 2018-03-12 14:45:19 INFO ThreadWaitDemo:65 - 厨房炒了一个:[鱼香肉丝],厨师歇息2分钟...当前菜架:[[红烧肉], [鱼香肉丝]] 2018-03-12 14:45:21 INFO ThreadWaitDemo:65 - 厨房炒了一个:[干煸豆角],厨师歇息2分钟...当前菜架:[[红烧肉], [鱼香肉丝], [干煸豆角]] 2018-03-12 14:45:25 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[红烧肉]...当前菜架:[[鱼香肉丝], [干煸豆角]] 2018-03-12 14:45:25 INFO ThreadWaitDemo:99 - 餐厅:厨房的储备菜品所剩不多时,厨师们该继续炒菜了... 2018-03-12 14:45:28 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[鱼香肉丝]...当前菜架:[[干煸豆角]] 2018-03-12 14:45:28 INFO ThreadWaitDemo:99 - 餐厅:厨房的储备菜品所剩不多时,厨师们该继续炒菜了... 2018-03-12 14:45:30 INFO ThreadWaitDemo:106 - 餐厅:刚刚消费了一道[干煸豆角]...当前菜架:[] 2018-03-12 14:45:30 INFO ThreadWaitDemo:90 - 餐厅:生意太好,菜品供不应求,只能等待厨房做菜...当前菜架:[] ...
相关文章推荐
- Java多线程Thread.yield(),thread.join(), Thread.sleep(200),Object.wait(),Object.notify(),Object.notifyAll()的区别
- Java中的Object的Wait() 和notify()方法使用时应注意的地方和Thread中的sleep()方法
- wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法
- 【Java并发系列02】Object的wait()、notify()、notifyAll()方法使用
- Java中的Object的Wait() 和notify()方法使用时应注意的地方和Thread中的sleep()方法
- Java中的Object的Wait() 和notify()方法使用时应注意的地方和Thread中的sleep()方法
- Java多线程之sleep(),yield(),wait(),notify(),notifyAll()等方法介绍
- 【Java之多线程(二)】(***重要***)Java多线程中常见方法的区别,如object.wait()和Thread.sleep()的区别等
- Java线程中sleep()、wait()和notify()和notifyAll()、yield()、join()等方法的用法和区别
- Java线程中sleep()、wait()和notify()和notifyAll()、yield()、join()等方法的用法和区别
- Java并发学习笔记(13)线程之间的协作(Object.wait(),notifu(),notifyAll() Thread.join())
- java notify()、 notifyAll()、 wait()、sleep()、yield()、join()方法学习
- 关于Java线程的sleep(),wait(),notify(),notifyall(),interrupt()等各种方法
- java object的wait和Thread的sleep方法区别
- 有关Object之wait(),notify() 和notifyAll() 以及Thread之sleep(),join()和yield()
- java.lang.Thread.sleep()方法和java.lang.Object.wait()方法之间的区别
- Java线程中sleep()、wait()和notify()和notifyAll()、yield()、join()等方法的用法和区别
- Java线程中sleep()、wait()和notify()和notifyAll()、yield()、join()等方法的用法和区别
- java 的 Thread_wait、notify、notifyAll的使用方法
- java Thread方法解析: sleep join wait notify notifyAll