Detailed explanation of Lock in Java

1. Introduction

java.util.concurrent.locks.Lock is a thread synchronization mechanism similar to synchronized blocks . But Lock is more flexible than synchronized blocks. Lock is an interface, and there is an implementation class called ReentrantLock.

2. The difference between Lock and syncronized

  • synchronized is a keyword in the Java language. Lock is an interface.
  • synchronized does not require the user to manually release the lock, and the lock is automatically released when an exception occurs or the thread ends; Lock requires the user to manually release the lock. If the lock is not actively released, it may lead to a deadlock.
  • Lock can be configured with a fair strategy to allow threads to acquire locks in order.
  • The trylock method is provided to try to acquire the lock. When the lock is acquired or cannot be acquired, different return values ​​are returned so that the program can handle it flexibly.
  • lock() and unlock() can be executed in different methods, and the same thread can lock() in the previous method and unlock() in other subsequent methods, which is much more flexible than syncronized.

3. Lock interface abstract method 

  • void lock(): Acquire the lock. If the lock is not available, the current thread will be disabled for thread scheduling purposes and sleep until the lock is acquired.
Lock lock = ...;
lock.lock();
try{
    //处理任务
}catch(Exception ex){
     
}finally{
    lock.unlock();   //释放锁
}
  • boolean tryLock(): Returns true immediately if the lock is available, returns false immediately if the lock is unavailable;
  • boolean tryLock(long time, TimeUnit unit) throws InterruptedException: If the lock is available, this method returns true immediately. If the lock is not available, the current thread will be disabled for thread scheduling purposes and sleep until one of the following three things occurs: ① the current thread acquires the lock; ② the current thread is interrupted by another thread, and Supports interrupt acquisition of locks; ③ If the lock is acquired after the specified waiting time, it returns true, if the lock is not acquired, it returns false.
Lock lock = ...;
if(lock.tryLock()) {
     try{
         //处理任务
     }catch(Exception ex){
         
     }finally{
         lock.unlock();   //释放锁
     } 
}else {
    //如果不能获取锁,则直接做其他事情
}

  • void unlock(): Release the lock. The operation of releasing the lock is performed in the finally block to ensure that the lock is definitely released and prevent deadlock from occurring.

四、ReentrantLock

Reentrancy lock is also called recursive lock, which means that after the outer function of the same thread acquires the lock, the inner recursive function still has the code to acquire the lock, but it is not affected. To avoid deadlock problems, synchronized can also be reentrant.

4.1. Synchronized reentrancy test

public class ReentrantDemo {
    public synchronized  void method1() {
        System.out.println("synchronized method1");
        method2();
    }
    public synchronized void method2() {
        System.out.println("synchronized method2");
    }
    public static void main(String[] args) {
        ReentrantDemo reentrantDemo = new ReentrantDemo();
        reentrantDemo.method1();
    }
}

Results of the

Insert image description here

4.2. ReentrantLock reentry test 

public class ReentrantDemo implements Runnable {
    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        set();
    }
    public void set() {
        try {
            lock.lock();
            System.out.println("set 方法");
            get();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();// 必须在finally中释放
        }
    }

    public void get() {

        try {
            lock.lock();
            System.out.println("get 方法");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        ReentrantDemo reentrantDemo = new ReentrantDemo();
        new Thread(reentrantDemo).start();
    }
}

Test results: The same thread first acquires the lock in the set method, then calls the get method, and repeatedly acquires the same lock in the get method. Both methods execute successfully.

Insert image description here

5. ReentrantReadWriteLock (read-write lock) 

Read-write locks can acquire read locks or write locks respectively. That is to say, the read and write operations of the data are separated and divided into two locks to be allocated to threads, so that multiple threads can perform read operations at the same time. Read locks use shared mode; write locks use exclusive mode ; read locks can be held by multiple threads at the same time when there is no write lock, and write locks are exclusive. When there is a read lock, the write lock cannot be obtained ; and when there is a write lock, except the thread that obtained the write lock can obtain the read lock, other threads cannot obtain the read lock.

  • writeLock(): Obtain the write lock.
  • readLock(): Obtain the read lock.
    Execute three threads to perform read and write operations, and set up a barrier. After the threads are ready in turn, they wait until they acquire the lock. When the third thread executes cyclicBarrier.await();, the barrier is lifted and the three threads execute at the same time.
public class WriteAndReadLockTest {
    private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10,
            60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
    private static int i = 100;
    public static void main(String[] args) {
        threadPoolExecutor.execute(()->{
            read(Thread.currentThread());
        });
        threadPoolExecutor.execute(()->{
            write(Thread.currentThread());
        });
        threadPoolExecutor.execute(()->{
            read(Thread.currentThread());
        });
        threadPoolExecutor.shutdown();
    }

    private static void read(Thread thread) {
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        reentrantReadWriteLock.readLock().lock();
        try {
            System.out.println("读线程 "+ thread.getName() + " 开始执行, i=" + i);
            Thread.sleep(1000);
            System.out.println(thread.getName() +" is over!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantReadWriteLock.readLock().unlock();

        }
    }
    private static void write(Thread thread) {
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        reentrantReadWriteLock.writeLock().lock();
        try {
            i++;
            System.out.println("写线程 "+ thread.getName() + " is doing, i=" + i);
            System.out.println(thread.getName() +" is over!");
        } finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }
}

 Execution result: Thread 1 acquires the read lock first, because the read lock can be shared, and all threads 3 can also acquire the read lock. After threads 1 and 3 complete the read operation and release the read lock, thread 2 can acquire the write lock. and start performing write operations.

Insert image description here

6. Fair lock and unfair lock 

  • Fair lock: It is very fair. In a concurrent environment, when acquiring a lock, each thread will first check the waiting queue maintained by this lock. If it is empty, or the current thread is the first in the waiting queue, it will occupy the lock, otherwise will be added to the waiting queue, and will be retrieved from the queue according to FIFO rules.
  • Unfair lock: It is relatively rude. It will directly try to occupy the lock. If the attempt fails, it will use a method similar to fair lock.

6.1. How to implement 

  • ReentrantLock: mode is unfair lock. Fair locks can also be created through construction methods;
public ReentrantLock() {
	sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
  • ReentrantReadWriteLock: The default is an unfair lock, and a fair lock can also be created through the construction method;
public ReentrantReadWriteLock() {
	this(false);
}
public ReentrantReadWriteLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
    readerLock = new ReadLock(this);
    writerLock = new WriteLock(this);
}

6.2 . Advantages and Disadvantages

Unfair lock performance is higher than fair lock performance. First, there is a significant delay between resuming a suspended thread and actually running it. Moreover, unfair locks can make fuller use of the CPU time slice and minimize the CPU idle state time.

7. Use of Condition

When certain conditions are met, the await() method of Condition is called to cause the current thread to enter sleep state and wait. Call Condition's signalAll() method to wake up the thread that went to sleep due to await().

Lock synchronization requires the user to manually control the acquisition and release of the lock. Its flexibility enables more complex multi-thread synchronization and higher performance, but at the same time, the user must capture the code running process in time after acquiring the lock. Exception in and release the lock in the finally code block.

Use Lock locks and their synchronization conditions to implement a producer-consumer model:

public class MessageStorageByLock {  
    private int maxSize;  
    private List<String> messages;  
  
    private final ReentrantLock lock;  
    private final Condition conditionWrite;//声明两个锁条件  
    private final Condition conditionRead;  
    public MessageStorageByLock(int maxSize) {  
        this.maxSize = maxSize;  
        messages = new LinkedList<String>();  
        lock = new ReentrantLock(true);//true修改锁的公平性,为true时,使用lifo队列来顺序获得锁  
        conditionWrite = lock.newCondition();//调用newCondition()方法,即new ConditionObject();  
        conditionRead = lock.newCondition();  
  
    }  
    public void set(String message){  
        //使用锁实现同步,获取所得操作,当锁被其他线程占用时,当前线程将进入休眠  
        lock.lock();  
        try{  
            while(messages.size() == maxSize){  
                    System.out.print("the message buffer is full now,start into wait()\n");  
                    conditionWrite.await();//满足条件时,线程休眠并释放锁。当调用 signalAll()时。线程唤醒并重新获得锁  
            }  
            Thread.sleep(100);  
            messages.add(message);  
            System.out.print("add message:"+message+" success\n");  
            conditionRead.signalAll();//唤醒因conditionRead.await()休眠的线程  
        }catch (InterruptedException e){  
            e.printStackTrace();  
        }finally {  
            lock.unlock();  
        }  
    }  
    public String get(){  
        String message = null;  
        lock.lock();  
        try{  
            while(messages.size() == 0){  
                conditionRead.await();  
                System.out.print("the message buffer is empty now,start into wait()\n");  
            }  
            Thread.sleep(100);  
            message = ((LinkedList<String>)messages).poll();  
            System.out.print("get message:"+message+" success\n");  
            conditionWrite.signalAll();  
        }catch (InterruptedException e){  
            e.printStackTrace();  
        }finally {  
            lock.unlock();  
        }  
        return message;  
    }  
}  
Modifier and Type Method and Description
void

lock()

get lock

void lockInterruptibly()

Acquire the lock unless the current thread is  interrupted  .

Condition newCondition()

Returns a new Condition bound to this instance Lockinstance.

boolean tryLock()

The lock can only be acquired when called.

boolean tryLock(long time, TimeUnit unit)

If it is idle within the given waiting time and the current thread has not been  interrupted, the lock is acquired.

void

unlock();

release lock

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
 
public interface Lock {
    void lock();
 
    void lockInterruptibly() throws InterruptedException;
 
    boolean tryLock();
 
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
 
    void unlock();
 
    Condition newCondition();
}

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Date;
 
public interface Condition {
 
    void await() throws InterruptedException;
 
    void awaitUninterruptibly();
 
    long awaitNanos(long nanosTimeout) throws InterruptedException;
 
    boolean await(long time, TimeUnit unit) throws InterruptedException;
 
    boolean awaitUntil(Date deadline) throws InterruptedException;
 
    void signal();
 
    void signalAll();
}

8. Code examples

8.1 , Demo1 (first demonstrate the reentrancy of the lock)

package com.szh.lock;
 
/**
 * 演示锁的可重入性
 */
public class Test01 {
 
    public synchronized void metthod1() {
        System.out.println("同步方法1");
        //线程执行 metthod1() 方法,默认 this 作为锁对象,
        //在 metthod1() 方法中调用了 method2() 方法,注意当前线程还是持有 this 锁对象的
        //method2() 同步方法默认的锁对象也是 this 对象, 要执行 method2() 必须先获得 this 锁对象,
        //当前 this 对象被当前线程持有,可以 再次获得 this 对象, 这就是锁的可重入性.
        //假设锁不可重入的话,可能会造成死锁
        method2();
    }
 
    public synchronized void method2() {
        System.out.println("同步方法2");
        method3();
    }
 
    public synchronized void method3() {
        System.out.println("同步方法3");
    }
 
    public static void main(String[] args) {
        Test01 obj=new Test01();
 
        new Thread(new Runnable() {
            @Override
            public void run() {
                obj.metthod1();
            }
        }).start();
    }
}

operation result 

8.2 , Demo2 (basic use of ReentrantLock)

package com.szh.lock;
 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * ReentrantLock 的基本使用
 */
public class Test02 {
 
    //定义一个显示锁
    static Lock lock=new ReentrantLock();
 
    public static void method() {
        //先获得锁
        lock.lock();
        //for循环此时就是同步代码块
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + " ---> " + i);
        }
        //释放锁
        lock.unlock();
    }
 
    public static void main(String[] args) {
        Runnable r=new Runnable() {
            @Override
            public void run() {
                method();
            }
        };
        //启动三个线程
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
    }
}

operation result

8.3 , Demo3 (use Lock to synchronize code blocks in different methods)

package com.szh.lock;
 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * 使用 Lock 锁同步不同方法中的同步代码块
 */
public class Test03 {
    //定义锁对象
    static Lock lock=new ReentrantLock();
 
    public static void method1() {
        //经常在 try 代码块中获得 Lock 锁, 在 finally 子句中释放锁
        try {
            lock.lock(); //获得锁
            System.out.println(Thread.currentThread().getName() + " ---method1--- " + System.currentTimeMillis());
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " ---method1--- " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock(); //释放锁
        }
    }
 
    public static void method2() {
        //经常在 try 代码块中获得 Lock 锁, 在 finally 子句中释放锁
        try {
            lock.lock(); //获得锁
            System.out.println(Thread.currentThread().getName() + " ---method2--- " + System.currentTimeMillis());
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " ---method2--- " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock(); //释放锁
        }
    }
 
    public static void main(String[] args) {
 
        Runnable r1=new Runnable() {
            @Override
            public void run() {
                method1();
            }
        };
 
        Runnable r2=new Runnable() {
            @Override
            public void run() {
                method2();
            }
        };
 
        new Thread(r1).start();
        new Thread(r1).start();
 
        new Thread(r2).start();
        new Thread(r2).start();
    }
}

operation result

8.4 , Demo4 (ReentrantLock lock reentrancy) 

package com.szh.lock;
 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * ReentrantLock 锁的可重入性
 */
public class Test04 {
 
    static class SubThread extends Thread {
        //定义锁对象
        private static Lock lock=new ReentrantLock();
 
        //定义变量
        private static int num=0;
 
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                try {
                    //可重入锁指可以反复获得该锁
                    lock.lock();
                    lock.lock();
                    num++;
                }finally {
                    lock.unlock();
                    lock.unlock();
                }
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
 
        SubThread t1=new SubThread();
        SubThread t2=new SubThread();
 
        t1.start();
        t2.start();
 
        t1.join();
        t2.join();
 
        System.out.println(SubThread.num);
    }
}

operation result

8.5 , Demo5 (lockInterruptibly() method of ReentrantLock)

package com.szh.lock;
 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * lockInterruptibly()方法
 *  如果当前线程未被中断则获得锁,
 *  如果当前线程被中断则出现异常.
 */
public class Test05 {
 
    static class Service {
        private Lock lock=new ReentrantLock(); //定义锁对象
        public void serviceMethod() {
            try {
                //lock.lock();  获得锁, 即使调用了线程的 interrupt() 方法, 也没有真正的中断线程
                //如果线程被中断了, 不会获得锁, 会产生异常
                lock.lockInterruptibly();
                System.out.println(Thread.currentThread().getName() + " --- begin lock");
                //执行一段耗时的操作
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    new StringBuilder();
                }
                System.out.println(Thread.currentThread().getName() + " --- end lock");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + " === 释放锁");
                lock.unlock(); //释放锁
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        Service s=new Service();
 
        Runnable r=new Runnable() {
            @Override
            public void run() {
                s.serviceMethod();
            }
        };
 
        Thread t1=new Thread(r);
        t1.start();
        Thread.sleep(50);
 
        Thread t2=new Thread(r);
        t2.start();
        Thread.sleep(50);
 
        t2.interrupt(); //中断 t2 线程
    }
}

operation result 

8.6 , Demo6 (lockInterruptibly() method can avoid deadlock) 

package com.szh.lock;
 
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * 通过 ReentrantLock 锁的 lockInterruptibly() 方法避免死锁的产生
 */
public class Test06 {
 
    static class MyLock implements Runnable {
 
        //创建两个ReentrantLock等锁对象
        private static ReentrantLock lock1=new ReentrantLock();
        private static ReentrantLock lock2=new ReentrantLock();
 
        int lockNum; //定义整数变量,决定使用哪个锁,偶数用lock1,奇数用lock2
 
        public MyLock(int lockNum) {
            this.lockNum=lockNum;
        }
 
        @Override
        public void run() {
            try {
                if (lockNum % 2 == 1) { //奇数, 先锁 1, 再锁 2
                    lock1.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + "获得锁1,还需要获得锁2");
                    Thread.sleep(1000);
                    lock2.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2");
                }else { //偶数, 先锁 2, 再锁 1
                    lock2.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + "获得了锁2,还需要获得锁1");
                    Thread.sleep(1000);
                    lock1.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2");
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                if (lock1.isHeldByCurrentThread()) { //判断当前线程是否持有该锁
                    lock1.unlock();
                }
                if (lock2.isHeldByCurrentThread()) {
                    lock2.unlock();
                }
                System.out.println(Thread.currentThread().getName() + "线程退出");
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        MyLock myLock1=new MyLock(11);
        MyLock myLock2=new MyLock(22);
 
        Thread t1=new Thread(myLock1);
        Thread t2=new Thread(myLock2);
        t1.start();
        t2.start();
 
        //在 main 线程, 等待 3000 ms, 如果还有线程没有结束就中断该线程
        Thread.sleep(1000 * 3);
        //可以中断任何一个线程来解决死锁, t2 线程会放弃对锁 1 的申请, 同时释放锁 2, t1 线程会完成它的任务
        if (t2.isAlive()) {
            t2.interrupt();
        }
    }
}

operation result

8.7 , Demo7 (ReentrantLock's tryLock(long time, TimeUnit unit) method) 

package com.szh.lock;
 
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * tryLock(long time, TimeUnit unit) 的作用在给定等待时长内,
 * 锁没有被另外的线程持有, 并且当前线程也没有被中断, 则获得该锁.
 * 通过该方法可以实现锁对象的限时等待.
 */
public class Test07 {
 
    static class TimeLock implements Runnable {
        private static ReentrantLock lock=new ReentrantLock(); //定义锁对象
 
        @Override
        public void run() {
            try {
                //假设 t1 线程先持有锁, 完成任务需要 4 秒钟,
                //这个时候 t2 线程尝试获得锁, t2 线程在 3 秒内还没有获得锁的话, 那么它就不再等了,直接放弃
                if (lock.tryLock(3, TimeUnit.SECONDS)) {
                    System.out.println(Thread.currentThread().getName() + "获得锁,执行耗时任务");
                    Thread.sleep(1000 * 4);
                    /*
                        假设 t1 线程先持有锁, 完成任务需要 2 秒钟
                        这个时候t2 线程尝试获得锁, t2 线程会一直尝试
                        在它约定尝试的 3 秒内可以获得锁对象
                     */
                    //Thread.sleep(1000 * 2);
                }else {
                    System.out.println(Thread.currentThread().getName() + "没有获得锁");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
    }
 
    public static void main(String[] args) {
        TimeLock timeLock=new TimeLock();
 
        Thread t1=new Thread(timeLock);
        Thread t2=new Thread(timeLock);
 
        t1.setName("t1");
        t2.setName("t2");
 
        t1.start();
        t2.start();
    }
}

operation result 

8.8 , Demo8 (tryLock() method of ReentrantLock)

package com.szh.lock;
 
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * tryLock() 当锁对象没有被其他线程持有的情况下, 才会获得该锁定
 */
public class Test08 {
 
    static class Service {
        private ReentrantLock lock=new ReentrantLock();
 
        public void serviceMethod() {
            try {
                if (lock.tryLock()) {
                    System.out.println(Thread.currentThread().getName() + "获得锁定");
                    Thread.sleep(1000 * 3); //模拟执行任务的时长
                }else {
                    System.out.println(Thread.currentThread().getName() + "没有获得锁定");
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        Service service=new Service();
 
        Runnable r=new Runnable() {
            @Override
            public void run() {
                service.serviceMethod();
            }
        };
 
        Thread t1=new Thread(r);
        t1.start();
        Thread.sleep(100);
        Thread t2=new Thread(r);
        t2.start();
    }
}

operation result

8.9 , Demo9 (tryLock() method can avoid deadlock)

package com.szh.lock;
 
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * 使用 tryLock() 可以避免死锁
 */
public class Test09 {
 
    static class MyLock implements Runnable {
 
        private static ReentrantLock lock1=new ReentrantLock();
        private static ReentrantLock lock2=new ReentrantLock();
 
        private int lockNum;
 
        public MyLock(int lockNum) {
            this.lockNum=lockNum;
        }
 
        @Override
        public void run() {
            if (lockNum % 2 == 0) { //偶数先锁 1, 再锁 2
                while (true) {
                    try {
                        if (lock1.tryLock()) {
                            System.out.println(Thread.currentThread().getName() + "获得了锁1,还想获得锁2");
                            Thread.sleep(50);
                            try {
                                if (lock2.tryLock()) {
                                    System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2,完成任务了");
                                    return;
                                }
                            } finally {
                                if (lock2.isHeldByCurrentThread()) {
                                    lock2.unlock();
                                }
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if (lock1.isHeldByCurrentThread()) {
                            lock1.unlock();
                        }
                    }
                }
            }else { //奇数就先锁 2, 再锁 1
                while (true) {
                    try {
                        if (lock2.tryLock()) {
                            System.out.println(Thread.currentThread().getName() + "获得了锁2,还想获得锁1");
                            Thread.sleep(50);
                            try {
                                if (lock1.tryLock()) {
                                    System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2,完成任务了");
                                    return;
                                }
                            } finally {
                                if (lock1.isHeldByCurrentThread()) {
                                    lock1.unlock();
                                }
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if (lock2.isHeldByCurrentThread()) {
                            lock2.unlock();
                        }
                    }
                }
            }
        }
    }
 
    public static void main(String[] args) {
        MyLock lock1=new MyLock(11);
        MyLock lock2=new MyLock(22);
 
        Thread t1=new Thread(lock1);
        Thread t2=new Thread(lock2);
 
        t1.start();
        t2.start();
        //运行后, 使用 tryLock() 尝试获得锁, 不会傻傻的等待, 通过循环不停的再次尝试, 如果等待的时间足够长, 线程总是会获得想要的资源
    }
}

operation result 

Guess you like

Origin blog.csdn.net/m0_50370837/article/details/124471888
Recommended