共享模型之管程(3)https://developer.aliyun.com/article/1530876
可打断
如果某个线程处于阻塞状态,可以调用其interrupt方法让其停止阻塞,获得锁失败
简而言之就是:处于阻塞状态的线程,被打断了就不用阻塞了,直接停止运行
public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(()-> { try { //加锁,可打断锁 //如果没有竞争那么此方法就会获取lock对象锁 //如果有竞争就进入阻塞队列,可以被其他线程用interrupt打断 lock.lockInterruptibly(); } catch (InterruptedException e) { e.printStackTrace(); //被打断,返回,不再向下执行 return; }finally { //释放锁 lock.unlock(); } }); lock.lock(); try { t1.start(); Thread.sleep(1000); //打断 t1.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }
主要防止线程死等
锁超时
使用lock.tryLock方法会返回获取锁是否成功。如果成功则返回true,反之则返回false。
并且tryLock方法可以指定等待时间,参数为:tryLock(long timeout, TimeUnit unit), 其中timeout为最长等待时间,TimeUnit为时间单位
简而言之就是:获取失败了、获取超时了或者被打断了,不再阻塞,直接停止运行
不设置等待时间
public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(()-> { //未设置等待时间,一旦获取失败,直接返回false if(!lock.tryLock()) { System.out.println("获取失败"); //获取失败,不再向下执行,返回 return; } System.out.println("得到了锁"); lock.unlock(); }); lock.lock(); try{ t1.start(); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }
设置等待时间
public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(()-> { try { //判断获取锁是否成功,最多等待1秒 if(!lock.tryLock(1, TimeUnit.SECONDS)) { System.out.println("获取失败"); //获取失败,不再向下执行,直接返回 return; } } catch (InterruptedException e) { e.printStackTrace(); //被打断,不再向下执行,直接返回 return; } System.out.println("得到了锁"); //释放锁 lock.unlock(); }); lock.lock(); try{ t1.start(); //打断等待 t1.interrupt(); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }Copy
公平锁
在线程获取锁失败,进入阻塞队列时,先进入的会在锁被释放后先获得锁。这样的获取方式就是公平的。
//默认是不公平锁,需要在创建时指定为公平锁 ReentrantLock lock = new ReentrantLock(true);
条件变量
synchronized 中也有条件变量,就是我们讲原理时那个 waitSet 休息室,当条件不满足时进入waitSet 等待
ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比
- synchronized 是那些不满足条件的线程都在一间休息室等消息
- 而 ReentrantLock 支持多间休息室,有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤 醒
使用要点:
- await 前需要获得锁
- await 执行后,会释放锁,进入 conditionObject 等待
- await 的线程被唤醒(或打断、或超时)取重新竞争 lock 锁
- 竞争 lock 锁成功后,从 await 后继续执
static Boolean judge = false; public static void main(String[] args) throws InterruptedException { ReentrantLock lock = new ReentrantLock(); //获得条件变量 Condition condition = lock.newCondition(); new Thread(()->{ lock.lock(); try{ while(!judge) { System.out.println("不满足条件,等待..."); //等待 condition.await(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("执行完毕!"); lock.unlock(); } }).start(); new Thread(()->{ lock.lock(); try { Thread.sleep(1); judge = true; //释放 condition.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }).start(); }
通过Lock与AQS实现可重入锁
public class MyLock implements Lock { private static class Sync extends AbstractQueuedSynchronizer { @Override protected boolean tryAcquire(int arg) { if (getExclusiveOwnerThread() == null) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } if (getExclusiveOwnerThread() == Thread.currentThread()) { int state = getState(); compareAndSetState(state, state + 1); return true; } return false; } @Override protected boolean tryRelease(int arg) { if (getState() <= 0) { throw new IllegalMonitorStateException(); } if (getExclusiveOwnerThread() != Thread.currentThread()) { throw new IllegalMonitorStateException(); } int state = getState(); if (state == 1) { setExclusiveOwnerThread(null); compareAndSetState(state, 0); } else { compareAndSetState(state, state - 1); } return true; } @Override protected boolean isHeldExclusively() { return getState() >= 1; } public Condition newCondition() { return new ConditionObject(); } } Sync sync = new Sync(); @Override public void lock() { sync.acquire(1); } @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, time); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.newCondition(); } } class Main { static int num = 0; public static void main(String[] args) throws InterruptedException, IOException { MyLock lock = new MyLock(); Object syncLock = new Object(); Thread t1 = new Thread(() -> { for (int i = 0; i < 10000; i++) { lock.lock(); try { lock.lock(); try { lock.lock(); try { num++; } finally { lock.unlock(); } } finally { lock.unlock(); } } finally { lock.unlock(); } } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 10000; i++) { lock.lock(); try { lock.lock(); try { lock.lock(); try { num--; } finally { lock.unlock(); } } finally { lock.unlock(); } } finally { lock.unlock(); } } }); t1.start(); t2.start(); t1.join(); t2.join(); int x = 0; } }Copy
13、同步模式之顺序控制
Wait/Notify版本
static final Object LOCK = new Object(); //判断先执行的内容是否执行完毕 static Boolean judge = false; public static void main(String[] args) { new Thread(()->{ synchronized (LOCK) { while (!judge) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("2"); } }).start(); new Thread(()->{ synchronized (LOCK) { System.out.println("1"); judge = true; //执行完毕,唤醒所有等待线程 LOCK.notifyAll(); } }).start(); }Copy
使用park往背包放东西
交替输出
wait/notify版本
public class Test4 { static Symbol symbol = new Symbol(); public static void main(String[] args) { new Thread(()->{ symbol.run("a", 1, 2); }).start(); new Thread(()->{ symbol.run("b", 2, 3); }).start(); symbol.run("c", 3, 1); new Thread(()->{ }).start(); } } class Symbol { public synchronized void run(String str, int flag, int nextFlag) { for(int i=0; i<loopNumber; i++) { while(flag != this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(str); //设置下一个运行的线程标记 this.flag = nextFlag; //唤醒所有线程 this.notifyAll(); } } /** * 线程的执行标记, 1->a 2->b 3->c */ private int flag = 1; private int loopNumber = 5; public int getFlag() { return flag; } public void setFlag(int flag) { this.flag = flag; } public int getLoopNumber() { return loopNumber; } public void setLoopNumber(int loopNumber) { this.loopNumber = loopNumber; } }Copy
await/signal版本
public class Test5 { static AwaitSignal awaitSignal = new AwaitSignal(); static Condition conditionA = awaitSignal.newCondition(); static Condition conditionB = awaitSignal.newCondition(); static Condition conditionC = awaitSignal.newCondition(); public static void main(String[] args) { new Thread(()->{ awaitSignal.run("a", conditionA, conditionB); }).start(); new Thread(()->{ awaitSignal.run("b", conditionB, conditionC); }).start(); new Thread(()->{ awaitSignal.run("c", conditionC, conditionA); }).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } awaitSignal.lock(); try { //唤醒一个等待的线程 conditionA.signal(); }finally { awaitSignal.unlock(); } } } class AwaitSignal extends ReentrantLock{ public void run(String str, Condition thisCondition, Condition nextCondition) { for(int i=0; i<loopNumber; i++) { lock(); try { //全部进入等待状态 thisCondition.await(); System.out.print(str); nextCondition.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { unlock(); } } } private int loopNumber=5; public int getLoopNumber() { return loopNumber; } public void setLoopNumber(int loopNumber) { this.loopNumber = loopNumber; } }