浅析JAVA Lock锁原理
同样是锁,先说说synchronized和lock的区别:
- synchronized是java关键字,是用c++实现的;而lock是用java类,用java可以实现
- synchronized可以锁住代码块,对象和类,但是线程从开始获取锁之后开发者不能进行控制和了解;lock则用起来非常灵活,提供了许多api可以让开发者去控制加锁和释放锁等等。
写个Demo
staticLocklock=newReentrantLock();publicstaticvoidmain(String[]args)throwsInterruptedException{
lock.lock();//其他没拿到锁的卡住不动
Threadthread=newThread(newRunnable(){
@Override
publicvoidrun(){
System.out.println("starttogetlockInterruptibly");
lock.unlock();//看看会发生什么,注释掉再看看
lock.lock();
System.out.println("拿到锁");
lock.unlock();
System.out.println("释放锁");
}
});
thread.start();
Thread.sleep(3000);
lock.unlock();
}
我们自己来手写一下lock接口的tryLock()、lock()和unLock()方法,实现我们自己的myLock。
publicclassMyLockimplementsLock{
//多并发调用0-未占用大于0-占用
AtomicIntegerstate=newAtomicInteger();
ThreadownerThread=newThread();
//等待锁的队列
LinkedBlockingQueuewaiters=newLinkedBlockingQueue();
@Override
publicvoidlock(){
if(!tryLock()){//先抢锁,所以是非公平锁
//没拿到锁,放到队列中去进行排队
waiters.add(Thread.currentThread());
//等待被唤醒
for(;;){
if(tryLock()){//非公平锁情况下,唤醒过来继续获取锁
waiters.poll();//获取锁成功把自己从队列中取出来
return;
}else//获取锁失败
LockSupport.park();//线程阻塞
}
}
}
@Override
publicbooleantryLock(){
if(state.get()==0){//如果锁没被占用
if(state.compareAndSet(0,1)){//如果成功拿到锁
ownerThread=Thread.currentThread();//占用锁线程改为当前线程
returntrue;
}
}
returnfalse;
}
@Override
publicvoidunlock(){
if(ownerThread!=Thread.currentThread())//占用锁线程不是当前线程无法释放锁
thrownewRuntimeException("非法调用,当前锁不属于你");
if(state.decrementAndGet()==0)//如果成功释放锁
ownerThread=null;//占用锁线程置空
//通知其他线程
//Threadthread=null;
//
//while((thread=waiters.peek())!=null)
//LockSupport.unpark(thread);
Threadthread=waiters.peek();//获取队列头部线程,线程还留在队列中
if(thread!=null){
LockSupport.unpark(thread);//取消阻塞
}
}
@Override
publicbooleantryLock(longtime,TimeUnitunit)throwsInterruptedException{
returnfalse;
}
@Override
publicConditionnewCondition(){
returnnull;
}
@Override
publicvoidlockInterruptibly()throwsInterruptedException{
}
}
几个注意点:
- 锁的占用状态state是AtomicInteger类型,底层原理是CAS,这是为了保证在多并发情况下线程安全问题;
- 当线程1释放锁成功时,获取队列头部线程但并不取出,因为非公平锁模式下,队列头部线程不一定能获取到锁;
- LockSupport的park()和unPark()方法是native方法,可以阻塞,唤醒线程;
Lock默认是非公平锁,上面实现的也是非公平锁,小伙伴们可以试一试。
公平锁和非公平锁区别:
先等待先获取锁是公平锁;先等待也不一定先获取锁,可能被突然到来的线程获取到是非公平锁;
公平锁的实现:
@Override
publicvoidlock(){
checkQueue();//线程来的时候先不获取锁,而是先检查队列中有没有等待的线程,如果有,直接放入队列,如果没有,再去获取锁
if(!tryLock()){//先抢锁,所以是非公平锁
//没拿到锁,放到队列中去进行排队
waiters.add(Thread.currentThread());
//等待被唤醒
for(;;){
if(tryLock()){//非公平锁情况下,唤醒过来继续获取锁
waiters.poll();//获取锁成功把自己从队列中取出来
return;
}else//获取锁失败
LockSupport.park();//线程阻塞
}
}
}
看完的小伙伴可以去看JDK提供的Lock源码啦。。
以上就是浅析JAVALock锁原理的详细内容,更多关于JAVALock锁原理的资料请关注毛票票其它相关文章!