概述
一、wait()、notify()、notifyAll()
-
wait()
:导致当前线程等待,直到另一个线程调用此对象的notify()
方法或notifyAll()
方法,或指定的时间已过。 即释放所拥有的monitor
,直到重新获得注意:
wait()
要在同步代码块中使用,是为了防止拥有notify()
的线程先执行了,导致死锁 -
notify()
和notifyAll()
:分别是唤醒单个线程和所有线程public class Wait { public static Object object = new Object(); static class Thread1 extends Thread { @Override public void run() { synchronized (object){ System.out.println(Thread.currentThread().getName() + "开始执行了"); try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程"+Thread.currentThread().getName() + "获得了锁"); } } } static class Thread2 extends Thread { @Override public void run() { synchronized (object) { object.notify(); //为什么还会执行下面这行代码? //notify()唤醒线程时,被唤醒的线程不能马上执行,而要等sychronized()代码块的内容执行完了,才会释放monitor给被唤醒的线程持有 System.out.println("线程" + Thread.currentThread().getName() + "调用了notify()"); } } } public static void main(String[] args) throws InterruptedException { Thread1 thread1 = new Thread1(); Thread2 thread2 = new Thread2(); thread1.start(); Thread.sleep(200); thread2.start(); } } --------------------------- Thread-0开始执行了 线程Thread-1调用了notify() 线程Thread-0获得了锁
/** * thread0.start(),这时thread-0获得monitor,开始执行, * 执行到resourceA.wait(),释放持有的monitor * * thread1.start()与thread0.start几乎同时执行,这时thread-1获得monitor, * 开始执行,执行到resourceA.wait(),释放持有的monitor * * 经过200ms的休眠后,thread-2开始执行,notifyAll, * 唤醒thread-0和thread-1,获得monitor的那个线程继续执行完代码 */ public class WaitNotifyAll implements Runnable { private static final Object resourceA = new Object(); public static void main(String[] args) throws InterruptedException { WaitNotifyAll r = new WaitNotifyAll(); Thread thread0 = new Thread(r); Thread thread1 = new Thread(r); Thread thread2 = new Thread(new Runnable() { @Override public void run() { synchronized (resourceA){ resourceA.notifyAll(); System.out.println("Thread2 notified."); } } }); thread0.start(); thread1.start(); Thread.sleep(200); thread2.start(); } @Override public void run() { synchronized (resourceA){ System.out.println(Thread.currentThread().getName() + " got resourceA lock."); try { System.out.println(Thread.currentThread().getName() + " waits to start."); resourceA.wait(); System.out.println(Thread.currentThread().getName() + "'s waiting to end"); } catch (InterruptedException e) { e.printStackTrace(); } } } } ----------------------- Thread-0 got resourceA lock. Thread-0 waits to start. Thread-1 got resourceA lock. Thread-1 waits to start. Thread2 notified. Thread-1's waiting to end Thread-0's waiting to end
二、Wait()的过程
- 步骤:
- 各个线程进入 Entry Set ,开始竞争monitor
- 获得锁的线程开始执行
- 在运行 wait() 方法后,线程释放锁,没有锁的线程只能等待
- 等待的线程被唤醒,然后去竞争 monitor ,即抢锁
- 获得锁的再次回到执行状态
- 执行结束后,释放锁,退出
三、生产者消费者模式
-
用wait/notify来实现生产者消费者模式
public class ProducerConsumerModel { public static void main(String[] args) { EventStorage storage = new EventStorage(); Producer producer = new Producer(storage); Consumer consumer = new Consumer(storage); new Thread(producer).start(); new Thread(consumer).start(); } } //生产者 class Producer implements Runnable{ private EventStorage storage; public Producer(EventStorage storage) { this.storage = storage; } @Override public void run() { for (int i = 0; i < 100; i++) { storage.put(); } } } //消费者 class Consumer implements Runnable { private EventStorage storage; public Consumer(EventStorage storage) { this.storage = storage; } @Override public void run() { for (int i = 0; i < 100; i++) { storage.take(); } } } //仓库 class EventStorage { private int maxSize; private LinkedList<Date> storage; public EventStorage() { maxSize = 10; storage = new LinkedList<>(); } //放入产品 public synchronized void put(){ while (storage.size() == 10){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } storage.add(new Date()); System.out.println("仓库有" + storage.size() + "个产品"); notify(); } //取出产品 public synchronized void take(){ while (storage.size() == 0){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("拿到了" + storage.poll() + ". 仓库还剩下" + storage.size()); notify(); } }
四、交替打印奇偶数
-
两个线程交替打印0~100的奇偶数
-
用
synchronized
实现/** * 一个线程用来打印偶数,一个线程用来打印奇数 */ public class WaitNotifyPrintOddEvenSyn { private static int count = 0; private static final Object lock = new Object(); public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { while (count < 100){ synchronized (lock) { if ((count & 1) == 0){ System.out.println(Thread.currentThread().getName() + ":" + count++); } } } } }, "偶数:").start(); new Thread(new Runnable() { @Override public void run() { while (count < 100){ synchronized (lock) { if ((count & 1) == 1){ System.out.println(Thread.currentThread().getName() + ":" + count++); } } } } }, "奇数:").start(); } }
-
使用
wait/notify
实现public class WaitNotifyPrintOddEveWait { private static int count = 0; private static final Object lock = new Object(); public static void main(String[] args) { new Thread(new TurningRunner(), "偶数").start(); new Thread(new TurningRunner(), "奇数").start(); } //1. 拿到锁就开始打印 //2. 打印完就notify其他线程,然后休眠 static class TurningRunner implements Runnable{ @Override public void run() { while (count < 100) { synchronized (lock) { System.out.println(Thread.currentThread().getName() + ":" + count++); lock.notify(); //打印未结束,让出当前线程的锁 if (count < 100) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } }
-
五、sleep()
-
sleep()
可以让线程进入
WAITING
状态,并且不占用CPU资源,但是不释放锁,直到规定时间后再执行,休眠期间如果被中断,会抛出异常并清除中断状态 -
wait()与sleep()的异同
相同:
- Wait和sleep方法都可以使线程阻塞,对应线程状态是Waiting或Time_Waiting
- wait和sleep方法都可以响应中断Thread.interrupt()
不同:
- wait()方法必须放在同步方法中执行,而sleep()则不用
- wait()方法执行会释放锁,而sleep()则不会
- sleep方法短暂休眠之后会主动退出阻塞,而没有指定时间的 wait方法则需要被
其他线程中断后才能退出阻塞。 - wait()属于Object类,sleep()属于Thread。wait()、notify()、notifyAll()都属于锁级别的操作,每个锁都绑定一个对象,而不是绑定在线程上,所以每个线程可以拥有多个锁;如果定义在Thread类中会限制锁的灵活使用
六、join()
-
join()
官方API文档的解释:
Waits for this thread to die.
即新加入的线程先执行,在join的过程中, 主线程的状态是
Waiting
/** * 执行thread.join和thread2.join后,main线程开始等待这两个子线程执行完了,再执行 */ public class Join { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行完毕"); } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行完毕"); } }); thread.start(); thread2.start(); System.out.println("子线程开始执行"); thread.join(); thread2.join(); System.out.println("所有线程执行完毕"); } } ------------------------ 子线程开始执行 Thread-0执行完毕 Thread-1执行完毕 所有线程执行完毕
-
join()
过程中的中断/** * 执行join的过程中,main线程是在等待子线程执行完毕,所以在join期间中断应该是main线程的中断 * 在执行过程中,发现在中断信号执行后,子线程依然在执行,这时要thread.interrupt中断子线程 * 避免主线程和子线程不一致 */ public class JoinInterrupt { public static void main(String[] args) { Thread mainThread = Thread.currentThread(); Thread thread = new Thread(new Runnable() { @Override public void run() { try { mainThread.interrupt(); Thread.sleep(5000); System.out.println("Thread0 finished."); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); System.out.println("等待子线程运行完毕"); try { thread.join(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + "中断了"); e.printStackTrace(); //thread.interrupt(); } System.out.println("子线程运行完毕"); } }
最后
以上就是开心大船为你收集整理的多线程核心5:Thread和Object类中线程相关方法的全部内容,希望文章能够帮你解决多线程核心5:Thread和Object类中线程相关方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复