LockSupport(锁支持):
四步走
来源
LockSupport 的本质:
就是用于线程等待唤醒机制的加强版本-->改良版本其中有两个特别的方法;
就是 wait()和 notify()的方法;
其中 object 类来说,wait()是让线程等待,notify()将线程唤醒;
juc 中 condition 的 await()让线程等待,使用 signal()方法唤醒线程;
标准的实现,生产者和消费者的模型:
1.利用 wait()和 notify()方法-->synchronized 的关键字,铁三角缺一不可:
package com.atguowang.thirdinterview.juc;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import java.util.concurrent.locks.LockSupport;
/** * @author lucas * @time 2020/10/27/10:29 * @description 锁对象,是什么,能干嘛,从哪里下,怎么玩 * AB学习法 **/public class TestLockSupport { //锁对象 static Object data = new Object();
public static void main(String[] args) { //打印 //System.out.println(Thread.currentThread().getName()+"\t"+"正在运行的线程");
new Thread(() -> { synchronized (data) { System.out.println(Thread.currentThread().getName() + "\t" + "---线程come in"); try { data.wait(); //等待操作
} catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t" + "被唤醒"); } }, "A").start();
//第二个线程开始唤醒;
new Thread(() -> { synchronized (data) { data.notify(); System.out.println(Thread.currentThread().getName() + "\t" + "通知"); }
}, "B").start(); }}
复制代码
解析:
当线程新建进入的时候,come in ,然后经过 wait 方法,,只能等着被 notify 之后,才可以执行后面的代码,、这里 synchronized 的锁对象是同一个,所以,其他的线程进入的时候可以直接,唤醒,也就是多个线程可以对可重入锁的(共同锁对象进行等待和唤醒),
异常情况 1:如果我们将 synchronized 直接删除掉,只是单纯的保留着 wait 和 notify(),还可以正常工作吗?
不能进入 wait;
Exception in thread "A" Exception in thread "B" java.lang.IllegalMonitorStateException
package com.atguowang.thirdinterview.juc;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import java.util.concurrent.locks.LockSupport;
/** * @author lucas * @time 2020/10/27/10:29 * @description 锁对象,是什么,能干嘛,从哪里下,怎么玩 * AB学习法 **/public class TestLockSupport { //锁对象 static Object data = new Object();
public static void main(String[] args) { //打印 //System.out.println(Thread.currentThread().getName()+"\t"+"正在运行的线程");
new Thread(() -> {// synchronized (data) { System.out.println(Thread.currentThread().getName() + "\t" + "---线程come in"); try { data.wait(); //等待操作
} catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t" + "被唤醒");// } }, "A").start();
//第二个线程开始唤醒;
new Thread(() -> {// synchronized (data) { data.notify(); System.out.println(Thread.currentThread().getName() + "\t" + "通知");// }
}, "B").start(); }}
复制代码
第二种情况异常:
如果我们将线程 wait->notify 的方法调换,先唤醒然后等待,会有什么异常呢
这种可以使用先让等待线程睡三秒,优先去执行唤醒的线程,试一下;
package com.atguowang.thirdinterview.juc;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import java.sql.Time;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.LockSupport;
/** * @author lucas * @time 2020/10/27/10:29 * @description 锁对象,是什么,能干嘛,从哪里下,怎么玩 * AB学习法 **/public class TestLockSupport { //锁对象 static Object data = new Object();
public static void main(String[] args) {
new Thread(() -> { //暂停几秒钟 try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (data) { System.out.println(Thread.currentThread().getName() + "\t" + "---线程come in"); try { data.wait(); //等待操作 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t" + "被唤醒"); } }, "A").start();
//第二个线程开始唤醒;
new Thread(() -> { synchronized (data) { data.notify(); System.out.println(Thread.currentThread().getName() + "\t" + "通知"); }
}, "B").start(); }}
复制代码
表示的时候--铁三角不能打破,或者说;wait 和 notify 的位置不能改变,如果说,一个线程中不能改变-->wait --->
package com.atguowang.thirdinterview.juc;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import java.sql.Time;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.LockSupport;
/** * @author lucas * @time 2020/10/27/10:29 * @description 锁对象,是什么,能干嘛,从哪里下,怎么玩 * AB学习法 **/public class TestLockSupport { //锁对象 static Object data = new Object();
public static void main(String[] args) {
new Thread(() -> { //暂停几秒钟 //try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (data) { System.out.println(Thread.currentThread().getName() + "\t" + "---线程come in"); try { data.wait(); //等待操作 System.out.println("处于被等待的状态"); data.notify(); System.out.println("处于一个唤醒的状态"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t" + "被唤醒"); } }, "A").start();
// 第二个线程开始唤醒;
new Thread(() -> { synchronized (data) { data.notify(); System.out.println(Thread.currentThread().getName() + "\t" + "通知"); }
}, "B").start(); }}
复制代码
还得保证具体的数据,我们将线程的转化为具体的使用,方法是一个简单的过程,如果说一个对象我们可以得到;
ReentrantLock 是 java.util.concurrent.Locks.ReentrantLock 的比较数据,然后我们将使用的过程直接变成具体的数据;这个对于重入互斥锁,synchronized 的扩展,
因为他有具体的 condition 的一个锁的状态--
ReentrantLock ----》代表的 await()和具体的 signal();
其中使用的 await()等方式就是在利用状态(condition)是一个接口。里面有默认的方法和具体的唤醒--等待阻塞;
lock()-->sync.lock()---》AQS
AbstractQueuedSynchronizer --》AQSAbstractQueuedSychronzier 查看 LockSupport 的显示结果--可以成为具体的数据展示;
JUC-->AQS-->LockSupport
卢卡寄语
当前可重入锁的底层 AQS,在底层就是锁支持,所以对于锁来说, 分类搞懂以后,对于最底层的知识,以不变应万变才是做好的,
晚安啦,我是卢卡,看完记得点赞哦
评论