- synchronized-wait-notify
static Object objectLock = new Object();
public static void syncWaitNotify()
{
new Thread(() -> {
//暂停几秒钟线程
// try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
synchronized (objectLock){
System.out.println(Thread.currentThread().getName()+"\t"+"---come in");
try {
objectLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t"+"---被唤醒");
}
},"t1").start();
//暂停几秒钟线程
// try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
synchronized (objectLock){
objectLock.notify();
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
}
},"t2").start();
}
RUN>
t1 ---come in t2 ---发出通知 t1 ---被唤醒
- wait-notify 不能脱离synchronized代码块单独运行
static Object objectLock = new Object();
public static void syncWaitNotify()
{
new Thread(() -> {
//暂停几秒钟线程
// try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
// synchronized (objectLock){
System.out.println(Thread.currentThread().getName()+"\t"+"---come in");
try {
objectLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t"+"---被唤醒");
// }
},"t1").start();
//暂停几秒钟线程
// try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
// synchronized (objectLock){
objectLock.notify();
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
// }
},"t2").start();
}
RUN>
t1 ---come in Exception in thread "t1" Exception in thread "t2" java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at com.atguigu.juc.interrupt.LockSupportDemo.lambda$syncWaitNotify$2(LockSupportDemo.java:83) at java.lang.Thread.run(Thread.java:748) java.lang.IllegalMonitorStateException at java.lang.Object.notify(Native Method) at com.atguigu.juc.interrupt.LockSupportDemo.lambda$syncWaitNotify$3(LockSupportDemo.java:96) at java.lang.Thread.run(Thread.java:748) Process finished with exit code 0
synchronized-wait-notify ,先notify后wait,线程运行会是什么情况
static Object objectLock = new Object();
public static void syncWaitNotify()
{
new Thread(() -> {
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
synchronized (objectLock){
System.out.println(Thread.currentThread().getName()+"\t"+"---come in");
try {
objectLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t"+"---被唤醒");
}
},"t1").start();
//暂停几秒钟线程
// try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
synchronized (objectLock){
objectLock.notify();
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
}
},"t2").start();
}
RUN>?????
t2 ---发出通知 t1 ---come in
Condition接口中的await后signal方法实现线程的等待和唤醒
- Condition-await-signal
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void lockAwaitSignal()
{
new Thread(() -> {
//暂停几秒钟线程
// try { TimeUnit.SECONDS.sleep(3); } 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();
}
},"t1").start();
new Thread(() -> {
lock.lock();
try
{
condition.signal();
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
}finally {
lock.unlock();
}
},"t2").start();
}
RUN>??????
t1 ---come in t2 ---发出通知 t1 ---被唤醒
- await-signal 不能脱离lock-unlock 单独使用
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void lockAwaitSignal()
{
new Thread(() -> {
//暂停几秒钟线程
// try { TimeUnit.SECONDS.sleep(3); } 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();
}
},"t1").start();
new Thread(() -> {
// lock.lock();
try
{
condition.signal();
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
}finally {
// lock.unlock();
}
},"t2").start();
}
RUN>??????
t1 ---come in Exception in thread "t1" Exception in thread "t2" java.lang.IllegalMonitorStateException at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1939) at com.atguigu.juc.interrupt.LockSupportDemo.lambda$lockAwaitSignal$1(LockSupportDemo.java:67) at java.lang.Thread.run(Thread.java:748) java.lang.IllegalMonitorStateException at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151) at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261) at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2036) at com.atguigu.juc.interrupt.LockSupportDemo.lambda$lockAwaitSignal$0(LockSupportDemo.java:54) at java.lang.Thread.run(Thread.java:748)
- Condition-await-signal 先signal后await
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void lockAwaitSignal()
{
new Thread(() -> {
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(3); } 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();
}
},"t1").start();
new Thread(() -> {
lock.lock();
try
{
condition.signal();
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
}finally {
lock.unlock();
}
},"t2").start();
}
RUN????????
t2 ---发出通知 t1 ---come in
Class LockSupport
- java.lang.Object
-
- java.util.concurrent.locks.LockSupport
public class LockSupport
extends Object
Basic thread blocking primitives for creating locks and other synchronization classes.
This class associates, with each thread that uses it, a permit (in the sense of the [Semaphore
](dfile:///Users/jiangbin/Library/Application Support/Dash/DocSets/Java_SE8/Java.docset/Contents/Resources/Documents/java/util/concurrent/Semaphore.html) class). A call to park
will return immediately if the permit is available, consuming it in the process; otherwise it may block. A call to unpark
makes the permit available, if it was not already available. (Unlike with Semaphores though, permits do not accumulate. There is at most one.)
- LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
- LockSupport类使用了一种名为Permit (许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),
- permit只有两个值1和零,默认是零。
- 可以把许可看成是一种(0,1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1。
- LockSupport不需要同步代码块,直接可以使用
park
unpark
挂起恢复线程运行(无锁块要求)
public static void main(String[] args)
{
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒");
}, "t1");
t1.start();
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
LockSupport.unpark(t1);
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
},"t2").start();
}
RUN>??????
t1 ---come in t2 ---发出通知 t1 ---被唤醒
- LockSupport - 先
unpark
后park
线程正常运行(支持先唤醒,后等待)
public static void main(String[] args)
{
Thread t1 = new Thread(() -> {
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒");
}, "t1");
t1.start();
new Thread(() -> {
LockSupport.unpark(t1);
System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
},"t2").start();
}
RUN>??????
t1 ---come in t2 ---发出通知 t1 ---被唤醒
重点说明(重要)
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
LockSupport是一个线程阻寒工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻寒之后也有对应的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码。
==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也不会积累凭证。
形象的理解
线程阻塞需要消耗凭证(permit), 这个凭证最多只有1个。
当调用park方法时
如果有凭证,则会直接消耗掉这个凭证然后正常退出;.
如果无凭证,就必须阻塞等待凭证可用;
而unpark则相反,它会增加一个凭证,但凭证最多只能有1个,累加无效。
为什么可以先唤醒线程后阻塞线程?
因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞。
为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?
因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证;
而调用两次park却需要消费两个凭证,证不够,不能放行。public static void main(String[] args) { Thread t1 = 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" + "---被唤醒"); }, "t1"); t1.start(); new Thread(() -> { LockSupport.unpark(t1); LockSupport.unpark(t1); System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知"); },"t2").start(); }