一 、常用的 两种 加锁方法
1、关键字 synchronized
2、ReentrantLock
官方ReentranLock 源码描述: A reentrant mutual exclusion {@link Lock} with the same basic behavior and semantics as the implicit monitor lock accessed using{@code synchronized} methods and statements,
but with extended capabilities.
翻译就是:
ReentranLock 具有与使用{@code synchronized}方法和语句访问的隐式监视锁相同的基本行为和语义的可重入互斥 但具有扩展功能。
二、锁住了什么?
1、synchronized
(1) 测试 2 个线程 ,执行任务时,Runnable 加锁 synchronized( this )或 synchronized(LockRunnable.this) => 当前访问 该 函数 的对象
- 接受 相同的 Runnabnle ==》 互斥顺序执行
0 :---start name{}Thread-020654264281 : --- end name{} Thread-01 :---start name{}Thread-120654264282 : --- end name{} Thread-1 - 接受不同的 Runnabnle ==》同时执行,
0 :---start name{}Thread-0
0 :---start name{}Thread-1
2065426428
2065426428
1 : --- end name{} Thread-0
1 : --- end name{} Thread-1
1 : --- end name{} Thread-1
3、锁在 方法 private syschronzied void print(){ .... }
(1 ) 接受 相同的 Runnable ==> 互斥顺序执行
( 2) 接受 不同的 Runnable ==> 同时执行
synchronized( this )
当线程接受的 Runnable 回调函数 不同时,出现 加锁无效的状况, 原因是 只是锁住的 是 this ( 当前对象 ),当 对象不一致时,锁好像 “失效了”
synchronized(类的静态变量时), 每个线程共享的内存变量,指向同一块内存区
在这里 是
synchronized (lockObj)
3、 接受不同的 Runnabnle ==》 互斥顺序执行, 打印的 lockObj 对象的hashcode 相同
0 :---start name{}Thread-0
799125565 #
1 : --- end name{} Thread-0
0 :---start name{}Thread-1
799125565
1 : --- end name{} Thread-1
syschronzied ( 变量) 锁住变量 锁的是 一个 指针,该指针执行 变量的内存区的头指针。
分配的内存区相同,即指针相同,例如 类的静态变量(存储在 多线程共享的内存区--》方法区 ,jvm 内存分配 )
this 关键词 当 多个 线程 接受 同一个对象时,既内存已经分派,同一块内存区 ,本质上是 每个线程都有自己的拷贝指针,但是 this 的 指针 相同,同理 接受不同的对象,不同的内存,不同的指针,锁住的不是同一个“地方”
private syschronzied void print(){ .... } 同理,锁在 不同对象的 同一个 方法上,虽然方法名相同,但是对象不同,对象的内存区不同,访问对象的 方法的 程序计数器 也不同(每个线程独有的内存区叫程序计数器
- (2)当被阻塞的线程 去哪了?
- 各自保存自己的程序执行到哪里),锁住的 不是同一个“地方”
-
-
2、ReentranLock 锁住了什么?
- 多个线程接受 不同的 runnable 时,使用 ReentranLock 也得是 静态的 static
-
- 1 、在保证 是 同一个 ReentranLock 对象时,查看 lock.lock()操作源码,通过控制获取线程安全的变量state互斥,实现了锁住一个 方法流程,
- -- 实现类是 NonfairSync, (1)计数,同一个线程下锁定的次数,可以实现多层锁定,unlock是 使状态值减少,state 变为0时,表示已经没有线程访问了
-
,final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
- 2、线程获取锁
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); // 当前 线程 int c = getState(); // 保存的 状态值 ,可以累加 if (c == 0) { // 当前没有 线程获取 if (compareAndSetState(0, acquires)) { // 线程安全设置 1,并保存 当前访问的线程, setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // state>0 表示已经有线程访问了,如果是 第一次访问的线程 int nextc = c + acquires; // 访问次数++,既是 锁的次数加,并保存次数 if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
- 2、线程获取锁
3、当被阻塞的线程去哪了? state >0 && 不是保存的 那个线程
构造一个Node 数据结构,加入了 等待队列,不间断的在 等待队列中 获取 线程 ,来获取 锁,没获得锁 ,自行中断
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; }
/** * Acquires in exclusive uninterruptible mode for thread already in * queue. Used by condition wait methods as well as acquire. * * @param node the node * @param arg the acquire argument * @return {@code true} if interrupted while waiting */ 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); } }
public class LockRunable implements Runnable { Integer count = 0; private static final ReentrantLock lock = new ReentrantLock( ); private static final Condition condThree = lock.newCondition(); private static final Condition condSix = lock.newCondition(); private static Object lockObj = new Object(); public static ReentrantLock getLock() { return lock; } @Override public void run() { synchronized ( lockObj ){ // lock.lock(); try { System. out.println(count + " :---start name{}" + Thread.currentThread().getName() ); System.out.println( lockObj.hashCode() ); Thread.currentThread().sleep( 400 ); // 模拟执行一个耗时的任务 // while ( count <=3 ){ count ++; // } System.out.println( ); // try {
public static void main(String[] args) { Runnable runnable1 = new LockRunable(); Runnable runnable = new LockRunable(); // 接受同一个 回调函数 Thread threadOne = new Thread( runnable ); Thread threadTwo = new Thread( runnable );
Thread threadTwo = new Thread( runnable1 ); // 第二次 测试threadOne.start(); threadTwo.start();
@Override public void run() { synchronized ( this ){ // lock.lock(); try { System. out.println(count + " :---start name{}" + Thread.currentThread().getName() ); System.out.println( lockObj.hashCode() ); Thread.currentThread().sleep( 400 ); // 模拟执行一个耗时的任务 // while ( count <=3 ){ count ++; // } System.out.println( ); // try { // condSix.signalAll(); // } catch (IllegalMonitorStateException e) { // e.printStackTrace(); // } System. out.println(count + " : --- end name{} " + Thread.currentThread().getName() ); } catch (InterruptedException e) { e.printStackTrace(); } finally { // lock.unlock(); }
@Override public void run() { // synchronized ( lockObj ){ // lock.lock(); print(); // // } } private synchronized void print(){ try { System. out.println(count + " :---start name{}" + Thread.currentThread().getName() ); System.out.println( lockObj.hashCode() ); Thread.currentThread().sleep( 400 ); // 模拟执行一个耗时的任务 // while ( count <=3 ){ count ++; // } System.out.println( ); // try {