曾经面试老被人问AQS,其实挺烦人的,我又不是作者,那记得那么多细节。原理我懂,给我个可以保证原子性的工具以及支持等待唤醒的工具,我自己也能实现。包括Redisson它也是利用了Redis的原子性和发布订阅功能来实现。
以下是利用synchronized 保证对state操作的原子性,还有wait/notify 支持等待唤醒实现的互斥锁
package com.example.demo;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyLock {
private int state = 0;
private long threadId = -1;
private final Object object = new Object();
public void lock(){
while(true){
if(state != 0) {
synchronized (object) {
if (state != 0) {
//未获取到锁
try {
object.wait();
} catch (InterruptedException e) {
//TODO 中断响应
}
}
}
}else{
synchronized (object) {
if (state != 0) {
//未获取到锁
try {
object.wait();
} catch (InterruptedException e) {
//TODO 中断响应
}
}else{
//获取到锁
threadId = Thread.currentThread().getId();
state += 1;
return;
}
}
}
}
}
public void unlock() {
if (threadId != Thread.currentThread().getId()) {
return;
}
if (state != 0) {
synchronized (object) {
if (state != 0) {
//释放成功
state -= 1;
threadId = -1;
object.notify();
return;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
testLock();
}
//测试无锁 输出是错的 我这边输出是997
public static void testNoLock() throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
int[] arrs = new int[]{0};
for(int i =0;i<1000;i++){
es.submit(()->{
arrs[0] += 1;
});
}
Thread.sleep(10000);
System.out.println(arrs[0]);
}
//测试锁 输出1000
public static void testLock() throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
int[] arrs = new int[]{0};
MyLock myLock = new MyLock();
for(int i =0;i<1000;i++){
es.submit(()->{
myLock.lock();
arrs[0] += 1;
myLock.unlock();
});
}
Thread.sleep(10000);
System.out.println(arrs[0]);
}
}
以下是共享锁
package com.example.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyShareLock {
private final int maxState;
private final long[] threadIdList;
MyShareLock(int maxState){
this.maxState = maxState;
this.threadIdList = new long[this.maxState];
}
MyShareLock(){
this(1);
}
private int state = 0;
private final Object object = new Object();
public void lock(){
while(true){
if(state == maxState) {
synchronized (object) {
if (state == maxState) {
//未获取到锁
try {
object.wait();
} catch (InterruptedException e) {
//TODO 中断响应
}
}
}
}else {
synchronized (object) {
if (state == maxState) {
//未获取到锁
try {
object.wait();
} catch (InterruptedException e) {
//TODO 中断响应
}
}else{
//获取到锁
threadIdList[state] = Thread.currentThread().getId();
state += 1;
return;
}
}
}
}
}
private int isHoldThread() {
synchronized (object) {
long currentThreadId = Thread.currentThread().getId();
for (int i = 0; i < threadIdList.length; i++) {
if (threadIdList[i] == currentThreadId) {
return i;
}
}
}
return -1;
}
public void unlock() {
int index;
if((index = isHoldThread()) == -1){
return;
}
if (state != 0) {
synchronized (object) {
if (state != 0) {
//释放成功
state -= 1;
threadIdList[index] = -1;
object.notify();
return;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
testLock();
}
//测试锁 输出是每10秒以上批量输出一次
public static void testLock() throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
int[] arrs = new int[]{0};
MyShareLock myShareLock = new MyShareLock(10);
for(int i =0;i<1000;i++){
es.submit(()->{
myShareLock.lock();
System.out.println(System.currentTimeMillis());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myShareLock.unlock();
});
}
Thread.sleep(100000);
System.out.println(arrs[0]);
}
}