JUC之AbstractQueuedSynchronizer-自定义锁
使用AbstractQueuedSynchronizer实现简单的自定义锁,为学习ReentrantLock做好铺垫。
(1)自定义实现类
MyLock通过继承AbstractQueuedSynchronizer,重写tryAcquire方法实现自定义获取锁的逻辑,重写tryRelease自定义实现释放锁的逻辑。设置state=1,即设置只有1把锁,每次同时只能有一个线程抢到这把锁,并且不支持重复获取。
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class MyLock extends AbstractQueuedSynchronizer {
/**
* 初始化state的值为1,表示只有1把锁可以抢
*/
public MyLock() {
setState(1);
}
public void lock() {
super.acquire(0);
}
public void unlock() {
super.release(1);
}
/**
* 分别重写tryAcquire、tryRelease方法自定义获取锁与释放锁的逻辑
*
*/
@Override
protected boolean tryAcquire(int arg) {
return compareAndSetState(1, 0);
}
@Override
protected boolean tryRelease(int arg) {
return compareAndSetState(0, 1);
}
}
(2)使用
count虽然使用了volatile保证线程可见性,但是count++不是原子性的,所以执行count++计算不是线程安全的。sell方法是普通方法,没有加锁来保证线程安全。sellWithLock方法使用自定义MyLock锁来保证线程安全。
使用1000个线程并发调用方法,对count++操作。如果满足线程安全,则最后打印的值必须为1000,否则不满足线程安全。
import java.util.concurrent.CountDownLatch;
public class Main {
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
/**
* 创建1000个线程调用方法,执行count++
*/
for (int i = 0; i < 1000; i++) {
new Thread(()->{
// main.sell();
main.sellWithLock();
countDownLatch.countDown();
}).start();
}
countDownLatch.await();
System.out.println("count的最后值:"+main.count);
}
private volatile int count = 0;
private MyLock myLock = new MyLock();
private static CountDownLatch countDownLatch = new CountDownLatch(1000);
private void sellWithLock() {
myLock.lock();
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
count++;
myLock.unlock();
}
private void sell() {
// 这边一定要让线程睡眠一会,不然在for循环调用的时候,
// 由于方法执行很快,会造成线程是一个一个依次执行的效果
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
count++;
}
}
(代码写的很粗糙,凑合着看吧。)
示例中使用到了CountDownLatch,其实现也是依赖于AbstractQueuedSynchronizer。
还没有评论,来说两句吧...