文章目录 等待/通知机制概念 等待/通知机制实现 wait()代码实例: wait()/notify()代码示例: interrupt()方法会中断wait() wait(long)方法的使用 notify()和notifyAl……
文
章
目
录
- 等待/通知机制概念
- 等待/通知机制实现
- wait()代码实例:
- wait()/notify()代码示例:
- interrupt()方法会中断wait()
- wait(long)方法的使用
- notify()和notifyAll()的区别
本文主要重点讲解Java多线程:线程间通信(等待/通知机制)问题。
等待/通知机制概念
等待/通知机制在我们生活中比比皆是,一个形象的例子就是厨师和服务员之间就存在等待/通知机制。
- 厨师做完一道菜的时间是不确定的,所以菜到服务员手中的时间是不确定的;
- 服务员就需要去“等待(wait)”;
- 厨师把菜做完之后,按一下铃,这里的按铃就是“通知(nofity)”;
- 服务员听到铃声之后就知道菜做好了,他可以去端菜了。
在Java多线程中理解就是:
等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()/notifyAll()
方法,线程A收到通知后退出等待队列,进入可运行状态,进而执行后续操作。上面这样的一个过程就是等待/通知机制。
等待/通知机制实现
Object类中的wait()方法,可以使执行当前代码的线程等待,暂停执行。直到接到通知或被中断为止。
注意:wait()方法只能在同步代码块中由锁对象调用,且调用wait()方法后,当前线程会释放锁。
Object类的notify()方法可以唤醒处于等待的线程,该方法也必须在同步代码块中由锁对象调用。如果有多个等待的线程,notify()只能唤醒其中一个,具体唤醒哪一个是不知道的。被notify()的线程需要重新去竞争锁才能被执行。
没有使用锁对象就调用wait()/notify()方法会产生异常:IllegalMonitorStateException。
wait()代码实例:
public class Test01 {
public static void main(String[] args) throws InterruptedException {
String test = \"abc\";
String another = \"def\";
System.out.println(\"同步代码块前的代码\");
synchronized (test) {
try {
System.out.println(\"wait前的代码\");
// another.wait(); 只有被锁住的对象才能调用wait()方法
test.wait();
System.out.println(\"wait后的代码\");
} catch (IllegalMonitorStateException e) {
e.printStackTrace();
}
}
System.out.println(\"同步代码块后的代码\");
}
}
wait()/notify()代码示例:
/**
* 需要通过notify唤醒线程
*/
public class Test02 {
public static void main(String[] args) {
String str = \"wa\";
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (str) {
System.out.println(\"线程1开始等待\");
try {
str.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(\"线程1被唤醒并执行结束了\");
}
}
}, \"Thread1\");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (str) {
System.out.println(\"线程2唤醒线程1\");
str.notify();
}
}
}, \"Thread2\");
thread1.start();
thread2.start();
}
}
执行了notify()的线程并不会立即释放锁,而是执行完同步代码块的所有代码后才会释放锁
interrupt()方法会中断wait()
当线程调用wait()处于等待状态时,调用线程对象的interrupt()方法会中断线程的等待状态,产生InterruptedException异常。
/**
* interrupt()会中断线程的wait状态
*/
public class Test04 {
public static void main(String[] args) throws InterruptedException {
SubThread subThread = new SubThread();
subThread.start();
TimeUnit.SECONDS.sleep(1);
subThread.interrupt();
}
private static final Object lock = new Object();
static class SubThread extends Thread {
@Override
public void run() {
synchronized (lock) {
System.out.println(\"subThread wait\");
try {
lock.wait();
} catch (InterruptedException e) {
System.out.println(\"wait等待被中断了\");
}
System.out.println(\"subThread end wait\");
}
}
}
}
wait(long)方法的使用
如果在指定时间内没有被唤醒,那么线程会自动唤醒。
public class Test06 {
public static void main(String[] args) {
SubThread subThread = new SubThread();
subThread.start();
}
static final Object lock = new Object();
static class SubThread extends Thread{
@Override
public void run() {
synchronized (lock) {
try {
System.out.println(\"开始等待\");
lock.wait(5000);
System.out.println(\"等待结束\");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
notify()和notifyAll()的区别
1) 唤醒数量不同
notify()方法只会随机唤醒等待队列中的一个线程,而notifyAll()方法则会唤醒等待队列中的所有线程。
2)调用方式不同
notify()和notifyAll()方法都必须在同步代码块中调用,并且必须包含在synchronized块中,且必须是该对象的监视器对象才能够调用。而且只有在获取了锁之后才能调用,否则会抛出IllegalMonitorStateException异常。
3) 竞争情况不同
notify()方法只会唤醒等待队列中的一个线程,并使其与其他线程竞争获取锁,这可能会导致某些线程无法被唤醒或者一直处于等待状态。
notifyAll()方法则会唤醒等待队列中的所有线程,并使它们竞争获取锁,这样可以使所有线程都有机会获取锁并进入运行状态,从而避免了一些线程一直处于等待状态。
总结
以上就是Java多线程:线程间通信(等待/通知机制)的基础内容,如下想要更深层次地理解该机制,可以参考下一篇文章:Java多线程:线程间通信(生产者消费者模式)
还没有评论呢,快来抢沙发~