在上文中,我们看到即使使用synchronized来实现泛型间的通信,我们应该结合Object中的配套方法wait()/notify()、wait()/notifyAll。我们先来说说一看Obejet中这系列方式的表明:
方法名称描述
wait()
调用该方式的线程处于WAITING状态,只有期待另外线程的通知或被中止才能返回,需要注意,线程读取wait()方法前,需要获取对象的监视器。当调用wait()方法后,会释放对象的监视器
wait(long)
调用该方式的轮询进入TIMED_WAITING状态,这里的参数时间是毫秒,等待对应毫秒事件,如果没有收到其他线程通知,则超时返回
wait(long,int)
调用该方式的轮询进入TIMED_WAITING状态,基本作用同wiat(long),第二个参数代表为纳秒,也就是等待时间为毫秒+纳秒。
notify()
通知一个在对象监视器上等待的轮询,使其从wait()方法返回,而返回的前提是该线程获得到了对象的监视器。
notifyAll()
通知所有在监视器上等待的线程,具体激活那个线程由CPU决定
使用Object的wait()/notify()、wait()/notifyall(),其实是我们常常使用的期待/通知体系,所谓的等待/通知体系是指一个线程A调用了对象O的wait()方法开启等待状态,而另一个线程B调用了对象O的notify或者notifyAll方法。线程A收到通知后从对象O的wait()方法返回,进而执行后续的操作。
下面,我们来借助一个例子来认识使用synchronized完成泛型的通信,具体实例如下所示:
class SynchronizedDemo {
static boolean flag = true;
static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(new WaitRunnable(), "WaitThread").start();
TimeUnit.SECONDS.sleep(1);//这里睡眠,是保证Wait线程先执行
new Thread(new NotifyRunnable(), "NotifyThread").start();
}
static class WaitRunnable implements Runnable {
@Override
public void run() {
synchronized (lock) {
while (flag) {//注意,通过while循环来判断条件
String name = Thread.currentThread().getName();
try {
System.out.println(name + "--->wait in " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "--->wake up in " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
}
static class NotifyRunnable implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (lock) {
System.out.println(name + "--->notify all in " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notifyAll();
flag = false;
}
/**
* 这里再次加锁,是为了验证当调用对象的notifyAll方法时,
* 如果线程不执行monitorexit(也就是释放锁),那么是不会唤醒其他线程的
*/
synchronized (lock) {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println(name + "--->hold lock again in " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
输出结果如下:

WaitThread--->wait in 23:10:11
NotifyThread--->notify all in 23:10:12
NotifyThread--->hold lock again in 23:10:14
WaitThread--->wake up in 23:10:14
从上文中,我们可以得出下面结论:
除了使用synchronized完成泛型的通信之外,我们还可以使用courrent包下的Lock接口,这里以ReentrantLock为例。具体实例如下所示:
class LockDemo {
static boolean flag = true;
static Lock lock = new ReentrantLock();
static Condition codition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
new Thread(new WaitRunnable(), "WaitThread").start();
TimeUnit.SECONDS.sleep(1);//这里睡眠,是保证Wait线程先执行
new Thread(new NotifyRunnable(), "NotifyThread").start();
}
static class WaitRunnable implements Runnable {
@Override
public void run() {
lock.lock();
try {
while (flag) {
String name = Thread.currentThread().getName();
System.out.println(name + "--->wait in " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
codition.await();
System.out.println(name + "--->wake up in " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
static class NotifyRunnable implements Runnable {
@Override
public void run() {
lock.lock();
try {
String name = Thread.currentThread().getName();
System.out.println(name + "--->notify all in " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
flag = false;
codition.signalAll();
} finally {
lock.unlock();
}
}
}
}
输出结果:
WaitThread--->wait in 23:39:34
NotifyThread--->notify all in 23:39:35
WaitThread--->wake up in 23:39:35
关于Lock使用及机理,大家可以查看下面几篇文章,这里就不再进行分析了。
从上面的事例中,我们可以总结并受到特别经典的期待/通知形式,该模式分别对于期待方法(消费者)和通知方(生产者)。
等待方依照如下原则:
获取对象的锁。如果条件不满足,那么条件不满足,那么调用对象的wait()方法。被通知后一直要再次检查条件。条件满足则执行相应逻辑。
对应伪代码分别如下:
使用synchronized方法:
synchronized(对象) {
while(条件不满足){
对象.wait();
}
对应的处理逻辑
}
使用lock模式:
lock.lock();
try{
while(条件不满足){
condition.wait();
}
}finally{
lock.unlock();
}
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-120751-2.html
一年估计只有加多宝赚的钱的零头的十分之一吧
中国还没有宣布这三个新岛的领海基点吧
懂吗
大家都很现实
现在需要探讨的是对美斗争的策略