第一种:使用Object类中的wait()和notify()方法实现线程等待和唤醒
正常案例:
public static void main(String[] args) {
Object object = new Object();
new Thread(() ->{
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
}
}, "A").start();
//暂停几秒
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
synchronized (object) {
object.notify();
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
}
}, "B").start();
}
异常案例一
public static void main(String[] args) {
Object object = new Object();
new Thread(() ->{
// synchronized (object) {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
// }
}, "A").start();
//暂停几秒
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
// synchronized (object) {
object.notify();
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
// }
}, "B").start();
}
结论:要使用必须包在synchronized 锁之间,必须先持有锁
异常案例二
public static void main(String[] args) {
Object object = new Object();
new Thread(() ->{
//暂停几秒
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
}
}, "A").start();
new Thread(() ->{
synchronized (object) {
object.notify();
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
}
}, "B").start();
}
结论二:将notify放在wait方法前面程序无法执行,无法唤醒
综上所述:wait和notify方法必须要在同步块或者方法里面,且成对出现,必须先wait后notify
第二种:Condition接口中的await后signal方法实现线程的等待和唤醒
正常案例
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
condition.await();
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
lock.lock();
try {
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
} finally {
lock.unlock();
}
}, "B").start();
}
异常案例
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(() -> {
// lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
condition.await();
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
// lock.unlock();
}
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
// lock.lock();
try {
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
} finally {
// lock.unlock();
}
}, "B").start();
}
结论:必须使用lock()和unlock()
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
condition.await();
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}, "A").start();
new Thread(()->{
lock.lock();
try {
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
} finally {
lock.unlock();
}
}, "B").start();
}
线程先要获得并持有锁,必须在锁块(synchronized或lock)中,必须要先等待后唤醒,线程才能够被唤醒
第三种:LockSupport类中的park等待和unpark唤醒
public static void main(String[] args) {
Thread thread1 = new Thread(() ->{
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
}, "A");
thread1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
LockSupport.unpark(thread1);
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
}, "B").start();
}
结论:无锁要求
public static void main(String[] args) {
Thread thread1 = new Thread(() ->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
}, "A");
thread1.start();
new Thread(() -> {
LockSupport.unpark(thread1);
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
}, "B").start();
}
可以先唤醒,再等待
异常案例
public static void main(String[] args) {
Thread thread1 = new Thread(() ->{
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
LockSupport.park();
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t ---- 被唤醒");
}, "A");
thread1.start();
new Thread(() -> {
LockSupport.unpark(thread1);
LockSupport.unpark(thread1);
System.out.println(Thread.currentThread().getName() + "\t ---- 发送通知");
}, "B").start();
}
结论: 许可的累加上限是1。