出处;https://www.liaoxuefeng.com/wiki/1252599548343744/1306581033549858
java线程锁是重入锁:一个线程可以重复获取锁
if (lock.tryLock(1, TimeUnit.SECONDS)) { try { ... } finally { lock.unlock(); } }
使用private final Lock lock = new ReentrantLock();
先去获取锁,然后再去铺获代码块
、最多等待1秒。如果1秒后仍未获取到锁,tryLock()
返回false
,不会无限等待下去。
所以,使用ReentrantLock
比直接使用synchronized
更安全,线程在tryLock()
失败的时候不会导致死锁
package com.example.demo.config; public class Thread1 extends Thread{ public void run() { System.out.println("Thread-1: try get lock A..."); synchronized (Demo.lockA) { //给A加锁 System.out.println("Thread-1: lock A got."); Demo.sleep1s(); System.out.println("Thread-1: try get lock B..."); synchronized (Demo.lockB) {//获取B锁 System.out.println("Thread-1: lock B got."); Demo.sleep1s(); } System.out.println("Thread-1: lock B released."); } System.out.println("Thread-1: lock A released."); } }
package com.example.demo.config; public class Thread2 extends Thread{ public void run() { System.out.println("Thread-2: try get lock B..."); synchronized (Demo.lockB) {//给B加锁 System.out.println("Thread-2: lock B got."); Demo.sleep1s(); System.out.println("Thread-2: try get lock A..."); synchronized (Demo.lockA) {//获取A锁 System.out.println("Thread-2: lock A got."); Demo.sleep1s(); } System.out.println("Thread-2: lock A released."); } System.out.println("Thread-2: lock B released."); } }
package com.example.demo.config; public class Demo { static final Object lockA = new Object(); static final Object lockB = new Object(); private Integer value=0; private Integer another=0; public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public Integer getAnother() { return another; } public void setAnother(Integer another) { this.another = another; } public void add(int m) { synchronized (lockA) { // 获得lockA的锁 System.out.println("获得lockA的锁0"); this.value += m; synchronized (lockB) { // 获得lockB的锁 System.out.println("获得lockB的锁0"); this.another += m; } // 释放lockB的锁 } // 释放lockA的锁 } public void dec(int m) { synchronized (lockB) { // 获得lockB的锁 System.out.println("获得lockB的锁1"); this.another -= m; synchronized (lockA) { // 获得lockA的锁 System.out.println("获得lockA的锁1"); this.value -= m; } // 释放lockA的锁 } // 释放lockB的锁 } static void sleep1s() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { new Thread1().start(); new Thread2().start(); Demo demo=new Demo(); try { demo.add(2); demo.dec(2); } catch (Exception e) { e.printStackTrace(); } } }
结果: Connected to the target VM, address: '127.0.0.1:51315', transport: 'socket' Thread-1: try get lock A... Thread-2: try get lock B... Thread-2: lock B got. Thread-1: lock A got. Thread-1: try get lock B... Thread-2: try get lock A... 造成死锁,
线程1 A加锁后获取B
线程2 B加锁后获取A
造成线程1获取B锁进入等待
线程2获取A锁进入等待,死循环下取
思维没有好的解决办法,只有停止虚拟机进行解决
使用ReentrantLock比直接使用synchronized更安全,可以替代synchronized进行线程同步。 但是,synchronized可以配合wait和notify实现线程在条件不满足时等待,条件满足时唤醒,用ReentrantLock我们怎么编写wait和notify的功能呢? 答案是使用Condition对象来实现wait和notify的功能。 我们仍然以TaskQueue为例,把前面用synchronized实现的功能通过ReentrantLock和Condition来实现
可见,使用Condition时,引用的Condition对象必须从Lock实例的newCondition()返回,这样才能获得一个绑定了Lock实例的Condition实例。 Condition提供的await()、signal()、signalAll()原理和synchronized锁对象的wait()、notify()、notifyAll()是一致的,并且其行为也是一样的: await()会释放当前锁,进入等待状态; signal()会唤醒某个等待线程; signalAll()会唤醒所有等待线程; 唤醒线程从await()返回后需要重新获得锁。 此外,和tryLock()类似,await()可以在等待指定时间后,如果还没有被其他线程通过signal()或signalAll()唤醒,可以自己醒来: if (condition.await(1, TimeUnit.SECOND)) { // 被其他线程唤醒 } else { // 指定时间内没有被其他线程唤醒 } 可见,使用Condition配合Lock,我们可以实现更灵活的线程同步。
package com.example.demo.config; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Demo { private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private Queue<String> queue = new LinkedList<>(); public void addTask(String s) throws InterruptedException { lock.lock(); try { queue.add(s); sleep(); condition.signalAll(); } finally { System.out.println("锁取消,全部唤醒"); lock.unlock(); } } public String getTask() throws InterruptedException { lock.lock(); try { while (queue.isEmpty()) { condition.await(); sleep(); System.out.println("等待了"); } return queue.remove(); } finally { System.out.println("锁取消,进行等待"); lock.unlock(); } } static void sleep() throws InterruptedException { Thread.sleep(1000); } public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(30, 100,//当前线程最大并发数 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(30),//候客区 Executors.defaultThreadFactory(), //new ThreadPoolExecutor.AbortPolicy() //满了,再进来的线程,不处理,直接抛异常 //new ThreadPoolExecutor.CallerRunsPolicy()//满了,返回回去,这里会让main线程处理 //new ThreadPoolExecutor.DiscardPolicy()//满了,再进来的线程,不处理,不会抛异常 new ThreadPoolExecutor.DiscardOldestPolicy()//满了,再进来的线程,尝试去获取cpu时间片,会与最早的线程竞争,不会抛异常 ); Demo demo = new Demo(); for (int i = 0; i < 9; i++) { threadPoolExecutor.execute(() -> { demo.addTask("abcd"); demo.getTask(); }); } boolean shutdown = threadPoolExecutor.isShutdown(); // threadPoolExecutor.wait(30000); if (shutdown) { threadPoolExecutor.shutdown(); } } }