1、Object的wait()与notify()
public class Test {
private static Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "开始执行");
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "结束执行");
}
}, "thread-1").start();
new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + "开始执行");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "结束执行");
}
}, "thread-2").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
lock.notify();
// lock.notifyAll();
}
}
}
注意:
1.操作必须位于synchronized
关键字内,必须持有锁
,否则会报异常IllegalMonitorStateException
;
2.wait()
会释放锁;
3.notify()
随机唤醒一个等待线程,notifyAll()
唤醒所有等待线程;
4.notify()/notifyAll()
位于wait()
之前会造成程序无法执行,一直处于等待过程中。
2、Condition的await()与single()
public class Test {
private static ReentrantLock reentrantLock = new ReentrantLock();
private static Condition condition = reentrantLock.newCondition();
public static void main(String[] args) {
new Thread(() -> {
reentrantLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "开始执行");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "结束执行");
} finally {
reentrantLock.unlock();
}
}, "thread-1").start();
new Thread(() -> {
reentrantLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "开始执行");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "结束执行");
} finally {
reentrantLock.unlock();
}
}, "thread-2").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
reentrantLock.lock();
try {
System.out.println("主线程发出通知=================》");
condition.signalAll();
}finally {
reentrantLock.unlock();
}
}
}
注意:
1.操作必须位于lock
范围内,必须持有锁
,否则会报异常IllegalMonitorStateException
;
2.await()
会释放锁;
3.signal()
随机唤醒一个等待线程,signalAll()
唤醒所有等待线程;
4.signal()/signalAll()
位于await()
之前会造成程序无法执行,一直处于等待过程中。
3、LockSupport的park()与unpark()
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。LockSupport类使用了一种名为Permit(许可)
的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit只有两个值1和零,默认是零
。可以把许可看成是一种(0,1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1
。
permit默认是0,所以一开始调用
park()
方法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,park方法会被唤醒,然后会将permit再次设置为0并返回。
调用unpark(thread)
方法后,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)会自动唤醒thread线程,即之前阻塞中的LockSupport.park()
方法会立即返回。
public class Test {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "开始执行");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "结束执行");
}, "thread-1");
Thread t2 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "开始执行");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "结束执行");
}, "thread-2");
t1.start();
t2.start();
LockSupport.unpark(t2);
}
}
注意:
1.LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,LockSupport是一个线程阻塞工具类,所有的方法都是静态方法
,可以让线程在任意位置阻塞
,阻塞之后也有对应的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码。
2.LockSupport提供park()和unpark()方法实现阻塞线程和解除线程阻塞的过程,LockSupport和每个使用它的线程都有一个许可(permit)关联。permit相当于1,0的开关,默认是0,
调用一次unpark就加1变成1, 调用一次park会消费permit,也就是将1变成0
,同时park立即返回。如再次调用park会变成阻塞(因为permit为零了会阻塞在这里,一直到permit变为1),这时调用unpark会把permit置为1。每个线程都有一个相关的permit, permit最多只有一个,重复调用unpark也不会积累凭证。
3.通俗理解
线程阻塞需要消耗凭证(permit),这个凭证最多只有1个。当调用park方法时
如果有凭证,则会直接消耗掉这个凭证然后正常退出
;
如果无凭证,就必须阻塞等待凭证可用
;
而unpark则相反,它会增加一个凭证,但凭证最多只能有1个,累加无效
。如以下案例t1会一直阻塞在此处
。