多线程锁有两种:
一种是用关键字 : syncronized实现
另一种是用Lock的实现类实现。 关于syncronized的解释可以参考一位博主写的(https://www.cnblogs.com/yuhangwang/p/11295940.html)
这里就先看ReentrantLock的实现,去窥探java的锁机制。
首先整体流程图如下:
示例代码:
public class TestTryLock implements Runnable { private static Lock locks = new ReentrantLock(); @Override public void run() { try { if(locks.tryLock(4, TimeUnit.SECONDS)){ // lock.lock() System.out.println(Thread.currentThread().getName()+"-->"); Thread.sleep(3000); }else{ System.out.println(Thread.currentThread().getName()+" time out "); } } catch (InterruptedException e) { // e.printStackTrace(); }finally { locks.unlock();//会抛出锁对象的异常,因为没有获取锁在unlock的时候出异常,可以先判断一下是否存在在执行。 } } public static void main(String[] args) throws InterruptedException { TestTryLock test =new TestTryLock(); Thread t1 = new Thread(test,"t1"); Thread t2 = new Thread(test,"t2"); Thread t3 = new Thread(test,"t3"); t1.start(); t2.start(); t1.join(); t2.join(); } }
示例用使用的是 ReentrantLock的非公平锁的实现,即线程不需要按照申请资源的顺序进行抢占锁资源。
通过使用lock.lock() 和lock.unlock()的配合,进行对资源的加解锁。
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
lock.lock() 是线程对资源进行绑定的操作,当线程占有了该共享资源(lock)的时候,会在 AQS同步器中的
exclusiveOwnerThread 属性设置当前抢占线程的值。 并将state设置为 1 。
如果没有抢占到资源的时候,就会走acquire(1)的路子。 也就是会将没有抢到锁的线程丢进等待队列中,这是一个FIFO队列
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
然后不断的进行自旋等待,判断前一节点是不是头节点,当原先抢占了资源锁的线程进行lock.unlock()等操作时,
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
也就是调用了AQS的release操作。 就会将state - 1 处理,一旦state == 0,则就说明可以释放锁了。
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
如果自旋等待的队列中某节点的前一节点是头节点,该节点就开始申请抢占 AQS中的
exclusiveOwnerThread。 如果成功了,就离开等待队列,进入到运行状态。
以上。
《Java高并发程序设计》 --通过ReentrantLock观望Java锁机制
原文:https://www.cnblogs.com/chenscript/p/14252886.html