最近刚刚通过了某大型游戏公司的技术面试,在和面试官交流中,主要都是谈及一些关于多线程开发中的锁原理。在以前的常规开发中,对于加锁操作而言经常会出现在多线程开发当中,所以对于锁的原理机制有必要花时间理一下,于是今晚写了这一篇文章。
队列同步器AbstractQueuedSynchronizer(AQS),这个东西似乎我们不经常用,但是它是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。
在以往的项目中我们有时候会用synchronized这个关键字来进行加锁,有的时候也会用jdk1.5之后出现的ReentrantLock来进行编写。主要还是看业务需求吧。
今天的案例是自己手写一个自定义独占锁,继承自lock接口,采用队列同步器来实现,以下是相应的代码部分:
首先是编写一个静态内部类Sync 继承自队列同步器,它在统一时刻只允许一个线程占有锁的资源,假如通过CAS设置同步状态为1以后,则表示同步状态设置成功了。
接下来便是代码部分的实现:
package com.sise.thread.Lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 作者:idea
* 日期:2018/6/25
* 描述:自己手写独占锁
*/
public class Mutex implements Lock {
private final Sync sync=new Sync();
private static class Sync extends AbstractQueuedSynchronizer{
//显示是否处于占用的状态
protected boolean isHeldExclusively(){
return getState()==1;
}
//尝试获取锁
@Override
protected boolean tryAcquire(int arg) {
if(compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
//释放锁
@Override
protected boolean tryRelease(int arg) {
if(getState()==0)
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
//返回一个condition队列
Condition newCondition() {
return new ConditionObject();
}
}
@Override
public void lock() {
sync.acquire(1);
}
public boolean isLock(){
return sync.isHeldExclusively();
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1,unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
public boolean hasQueuedThreads(){
return sync.hasQueuedThreads();
}
}
当这个独占锁的代码编写完成之后便是相应的测试部分了:
package com.sise.thread.Lock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 作者:idea
* 日期:2018/6/25
* 描述:测试独占锁
*/
public class TestMutex {
public List list=new ArrayList();
public Lock lock=new Mutex();
public void insert(){
try {
lock.lock();
for(int i=0;i<100;i++){
list.add(i);
Thread.sleep(10);
}
System.out.println(list.size());
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
final TestMutex t=new TestMutex();
new Thread(){
public void run(){
t.insert();
}
}.start();
new Thread(){
public void run(){
t.insert();
}
}.start();
}
}
最终测试发现,两个线程的运行分别同被自定义的独占锁所保护,因此不会出现线程安全问题。

假设将锁去掉之后,控制台的数据可能就会出现不一样的结果了


678

被折叠的 条评论
为什么被折叠?



