1.AQS是什么?
AQS(AbstractQueuedSynchronizer)形象队列同步器,是JDK下提供的一套实现基于FIFO期待队列的阻塞锁和相干同步器的一个同步框架.
根底:
- 线程:把握Java线程
- 锁:明确什么是锁
- 高并发(可选)
在Java新版本 里实现锁的框架
Public class Main { public static int m = 0;//动态成员变量 public static void main(String[] args) throws Exception{ Thread[] threads = new Thread[100];//定义一个线程数组 for(int i=0; i<threads.length; i++) { threads[i] = new Thread(()->{ for(int j=0; j<100; j++) m++; }); } for(Thread t : threads) t.start();//开始运行所有线程 for(Thread t : threads) t.join();//期待所有线程完结 System.out.println(m); }}/*这时候运行的后果并不精确*//*值会小于10000*/
如果这么写,运行后果并不精确;其起因是:
如果m=0始终++到100,当第一个线程m++,另一个线程也拿过去加,当第一个线程始终加到99时返回,而另一个线程也加到99返回,这样一来m原本应该是+2返回,但只加了1就返回 ;
那么如何解决这个问题:加锁,
加锁概念
是把锁在Main.class身上,锁的是对象,监听的是对象。
给其加锁后,当一个线程执行时,另一个线程也要来执行时,发现锁被占用,就会产生阻塞,直到被锁上的线程执行完。
其余线程在争这把锁,谁争到谁就执行,这样就防止了俩个线程同时执行。
2.synchronized() 同步锁
- 为什么应用synchronized在并发编程中存在线程平安问题,次要起因:1.存在共享数据 2.多线程独特操作共享数据.关键词synchronized能够保障在同一时刻只有一个线程能够执行某个办法或某个代码块,同时synchronized能够保障一个线程的变动可见.
- synchronized的三种利用形式一般同步办法(实例),锁是以后实例对象,进入同步代码前要取得以后实例的锁。动态同步办法,锁是以后类的class对象,进入同步代码前要取得以后类对象的锁。同步办法块,锁是括号外面的对象,对给定对象加锁,进入同步代码库前要取得给定对象的锁。
- synchronized的作用确保线程互斥拜访同步代码。保障共享变量的批改可能及时可见。解决重排序问题。
例:
Public class Main { public static int m = 0;//动态成员变量 public static void main(String[] args) throws Exception{ Thread[] threads = new Thread[100];//定义一个线程数组 for(int i=0; i<threads.length; i++) { threads[i] = new Thread(()->{ /*这里锁的是对象*/ synchronized (Main.class){ for(int j=0; j<100; j++) m++; } }); } for(Thread t : threads) t.start();//开始运行所有线程 for(Thread t : threads) t.join();//期待所有线程完结 System.out.println(m); }}
3.ReentrantLock() 重入锁
ReentrantLock底层实现就是AQS
ReentranLock个性(比照synchronized)
- 尝试取得锁
- 获取到锁的线程可能响应中断
例:
Public class Main { public static int m = 0;//动态成员变量 public static Lock lock = new ReentrantLock();//这里定义一把锁 public static void main(String[] args) throws Exception{ Thread[] threads = new Thread[100];//定义一个线程数组 for(int i=0; i<threads.length; i++) { threads[i] = new Thread(()->{ /*必须要用try finally*/ try{ lock.lock();//上锁 for(int j=0; j<100; j++) m++; } finally{ lock.unlock();//解锁 } }); } for(Thread t : threads) t.start();//开始运行所有线程 for(Thread t : threads) t.join();//期待所有线程完结 System.out.println(m); }}
4.CountDownLatch
CountDownLatch是Java中自带的锁,它的实现也是基于AQS
import java.util.concurrent.CountDownLatch;import java.util.concurrent.locks.Lock;/** * java本身带的锁:CountDownLatch */public class CountDown { public static int m = 0; public static Lock lock =new Mylock(); public static CountDownLatch latch = new CountDownLatch(100);//给其一个值,为100,当所有线程完结值为零 public static void main(String[] args) throws InterruptedException { Thread[] threads = new Thread[100]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(()->{ try { lock.lock(); for (int j = 0; j < 100; j++) m++; }finally { lock.unlock(); } latch.countDown();//每次调用减一 }); } for (Thread t: threads) t.start(); latch.await();//期待latch关上,当值变为0时关上,当所有线程执行完后值变为0 System.out.println(m); }}
5.应用AQS自定义锁
AQS的应用:
在AQS外部有一个int类型的值:State,在这个数根底之上治理着一个双向队列,当有新的线程去拜访这个值的时候,如果没有竞争不到拜访权,就在加在这个队列之后
应用Lock接口来写实现类,应用AQS来实现锁
import java.util.concurrent.locks.AbstractQueuedSynchronizer;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.AbstractQueuedSynchronizer;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;public class Mylock implements Lock{ private Sync sync = new Sync(); @Override public void lock() { sync.acquire(1);//调用acquire,不是当下写的Tryacquire } @Override public void lockInterruptibly() throws InterruptedException { } @Override public boolean tryLock() { return false; } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } @Override public void unlock() { } @Override public Condition newCondition() { return null; } /*类名Sync,继承AbstractQueuedSynchronizer*/ public class Sync extends AbstractQueuedSynchronizer{ @Override /*重写 tryAcqurie办法 */ protected boolean tryAcquire(int arg) { assert arg == 1; //在JDKAPI文档中,要求要传进来一个1,所以用assert〔〕 if (compareAndSetState(0,1)) {//这里应用到了CAS /*CAS:判断传进去的值,如果是0将其变为1*/ //判断m的值,如果是零将其变为1 setExclusiveOwnerThread(Thread.currentThread());//互斥锁 return true; } return false; } @Override /*开释*/ protected boolean tryRelease(int arg) { assert arg == 1; /*判断以后线程是否持有这把锁*/ if(!isHeldExclusively()) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } @Override protected boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread();//拿到以后领有的排它的线程和以后线程是否一样 } }}
这里所介绍的锁都是基于AQS来实现.
举荐浏览
字节跳动总结的设计模式 PDF 火了,完整版凋谢分享
刷Github时发现了一本阿里大神的算法笔记!标星70.5K
月薪没有达到 30K 的Java程序员 是听不懂这个我的项目的
为什么阿里巴巴的程序员成长速度这么快,看完他们的内部资料我懂了
程序员达到50W年薪所须要具备的常识体系。
对于【暴力递归算法】你所不晓得的思路
看完三件事❤️
如果你感觉这篇内容对你还蛮有帮忙,我想邀请你帮我三个小忙:
点赞,转发,有你们的 『点赞和评论』,才是我发明的能源。
关注公众号 『 Java斗帝 』,不定期分享原创常识。
同时能够期待后续文章ing????