当前位置:   article > 正文

Java中的Lock详解_java lock锁

java lock锁

一、简介

java.util.concurrent.locks.Lock 是一个类似于synchronized 块的线程同步机制。但是 Lock比 synchronized 块更加灵活。Lock是个接口,有个实现类是ReentrantLock。

二、Lock和syncronized的区别

  • synchronized是Java语言的关键字。Lock是一个接口。
  • synchronized不需要用户去手动释放锁,发生异常或者线程结束时自动释放锁;Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
  • lock可以配置公平策略,实现线程按照先后顺序获取锁。
  • 提供了trylock方法 可以试图获取锁,获取到或获取不到时,返回不同的返回值 让程序可以灵活处理。
  • lock()和unlock()可以在不同的方法中执行,可以实现同一个线程在上一个方法中lock()在后续的其他方法中unlock(),比syncronized灵活的多。

三、Lock接口抽象方法 

void lock():获取锁,如果锁不可用,则出于线程调度的目的,当前线程将被禁用,并且在获取锁之前处于休眠状态。

  1. Lock lock = ...;
  2. lock.lock();
  3. try{
  4. //处理任务
  5. }catch(Exception ex){
  6. }finally{
  7. lock.unlock(); //释放锁
  8. }

boolean tryLock():如果锁可用立即返回true,如果锁不可用立即返回false;
boolean tryLock(long time, TimeUnit unit) throws InterruptedException:如果锁可用,则此方法立即返回true。 如果该锁不可用,则当前线程将出于线程调度目的而被禁用并处于休眠状态,直到发生以下三种情况之一为止:①当前线程获取到该锁;②当前线程被其他线程中断,并且支持中断获取锁;③经过指定的等待时间如果获得了锁,则返回true,没获取到锁返回false。

  1. Lock lock = ...;
  2. if(lock.tryLock()) {
  3. try{
  4. //处理任务
  5. }catch(Exception ex){
  6. }finally{
  7. lock.unlock(); //释放锁
  8. }
  9. }else {
  10. //如果不能获取锁,则直接做其他事情
  11. }

void unlock():释放锁。释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

四、ReentrantLock

重入锁也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。避免死锁问题的,synchronized也可重入。

4.1、synchronized重入测试

  1. public class ReentrantDemo {
  2. public synchronized void method1() {
  3. System.out.println("synchronized method1");
  4. method2();
  5. }
  6. public synchronized void method2() {
  7. System.out.println("synchronized method2");
  8. }
  9. public static void main(String[] args) {
  10. ReentrantDemo reentrantDemo = new ReentrantDemo();
  11. reentrantDemo.method1();
  12. }
  13. }

 在这里插入图片描述

 4.2、ReentrantLock重入测试 

  1. public class ReentrantDemo implements Runnable {
  2. Lock lock = new ReentrantLock();
  3. @Override
  4. public void run() {
  5. set();
  6. }
  7. public void set() {
  8. try {
  9. lock.lock();
  10. System.out.println("set 方法");
  11. get();
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. } finally {
  15. lock.unlock();// 必须在finally中释放
  16. }
  17. }
  18. public void get() {
  19. try {
  20. lock.lock();
  21. System.out.println("get 方法");
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. } finally {
  25. lock.unlock();
  26. }
  27. }
  28. public static void main(String[] args) {
  29. ReentrantDemo reentrantDemo = new ReentrantDemo();
  30. new Thread(reentrantDemo).start();
  31. }
  32. }

测试结果:同一个线程,首先在set方法中获取锁,然后调用get方法,get方法中重复获取同一个锁。两个方法都执行成功。

 在这里插入图片描述

 五、ReentrantReadWriteLock(读写锁) 

读写锁,可以分别获取读锁或写锁。也就是说将数据的读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作。读锁使用共享模式;写锁使用独占模式;读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁

writeLock():获取写锁。
readLock():获取读锁。
执行三个线程进行读写操作,并设置一个屏障,线程依次准备就绪后未获取锁之前都在等待,当第三个线程执行 cyclicBarrier.await();后屏障解除,三个线程同时执行。
 

  1. public class WriteAndReadLockTest {
  2. private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
  3. private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10,
  4. 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
  5. private static CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
  6. private static int i = 100;
  7. public static void main(String[] args) {
  8. threadPoolExecutor.execute(()->{
  9. read(Thread.currentThread());
  10. });
  11. threadPoolExecutor.execute(()->{
  12. write(Thread.currentThread());
  13. });
  14. threadPoolExecutor.execute(()->{
  15. read(Thread.currentThread());
  16. });
  17. threadPoolExecutor.shutdown();
  18. }
  19. private static void read(Thread thread) {
  20. try {
  21. cyclicBarrier.await();
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. } catch (BrokenBarrierException e) {
  25. e.printStackTrace();
  26. }
  27. reentrantReadWriteLock.readLock().lock();
  28. try {
  29. System.out.println("读线程 "+ thread.getName() + " 开始执行, i=" + i);
  30. Thread.sleep(1000);
  31. System.out.println(thread.getName() +" is over!");
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. } finally {
  35. reentrantReadWriteLock.readLock().unlock();
  36. }
  37. }
  38. private static void write(Thread thread) {
  39. try {
  40. cyclicBarrier.await();
  41. } catch (InterruptedException e) {
  42. e.printStackTrace();
  43. } catch (BrokenBarrierException e) {
  44. e.printStackTrace();
  45. }
  46. reentrantReadWriteLock.writeLock().lock();
  47. try {
  48. i++;
  49. System.out.println("写线程 "+ thread.getName() + " is doing, i=" + i);
  50. System.out.println(thread.getName() +" is over!");
  51. } finally {
  52. reentrantReadWriteLock.writeLock().unlock();
  53. }
  54. }
  55. }

执行结果:线程1先获取到了读锁,因为读锁时可以共享的,所有线程3也可以获取到读锁,线程1、3读操作完成后将读锁释放后,线程2才能获取到写锁并开始执行写操作。

 在这里插入图片描述

 六、公平锁与非公平锁 

公平锁:就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO的规则从队列中取到自己
非公平锁:比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式

6.1、如何实现 

ReentrantLock:模式是非公平锁。也可通过构造方法创建公平锁;

  1. public ReentrantLock() {
  2. sync = new NonfairSync();
  3. }
  4. public ReentrantLock(boolean fair) {
  5. sync = fair ? new FairSync() : new NonfairSync();
  6. }

​​​​​​​ReentrantReadWriteLock:默认是非公平锁,也可以通过构造方法创建公平锁;

  1. public ReentrantReadWriteLock() {
  2. this(false);
  3. }
  4. public ReentrantReadWriteLock(boolean fair) {
  5. sync = fair ? new FairSync() : new NonfairSync();
  6. readerLock = new ReadLock(this);
  7. writerLock = new WriteLock(this);
  8. }

6.2优缺点

非公平锁性能高于公平锁性能。首先,在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。而且,非公平锁能更充分的利用cpu的时间片,尽量的减少cpu空闲的状态时间。

七、Condition的使用

当满足一定条件时,调用Condition的await()方法使当前线程进入休眠状态进行等待。调用ConditionsignalAll()方法唤醒因await()进入休眠的线程。

Lock锁实现同步时需要使用者手动控制锁的获取和释放,其灵活性使得可以实现更复杂的多线程同步和更高的性能,但同时,使用者一定要在获取锁后及时捕获代码运行过程中的异常并在finally代码块中释放锁。

使用Lock锁及其同步条件来实现一个生产者-消费者模型:

  1. public class MessageStorageByLock {
  2. private int maxSize;
  3. private List<String> messages;
  4. private final ReentrantLock lock;
  5. private final Condition conditionWrite;//声明两个锁条件
  6. private final Condition conditionRead;
  7. public MessageStorageByLock(int maxSize) {
  8. this.maxSize = maxSize;
  9. messages = new LinkedList<String>();
  10. lock = new ReentrantLock(true);//true修改锁的公平性,为true时,使用lifo队列来顺序获得锁
  11. conditionWrite = lock.newCondition();//调用newCondition()方法,即new ConditionObject();
  12. conditionRead = lock.newCondition();
  13. }
  14. public void set(String message){
  15. //使用锁实现同步,获取所得操作,当锁被其他线程占用时,当前线程将进入休眠
  16. lock.lock();
  17. try{
  18. while(messages.size() == maxSize){
  19. System.out.print("the message buffer is full now,start into wait()\n");
  20. conditionWrite.await();//满足条件时,线程休眠并释放锁。当调用 signalAll()时。线程唤醒并重新获得锁
  21. }
  22. Thread.sleep(100);
  23. messages.add(message);
  24. System.out.print("add message:"+message+" success\n");
  25. conditionRead.signalAll();//唤醒因conditionRead.await()休眠的线程
  26. }catch (InterruptedException e){
  27. e.printStackTrace();
  28. }finally {
  29. lock.unlock();
  30. }
  31. }
  32. public String get(){
  33. String message = null;
  34. lock.lock();
  35. try{
  36. while(messages.size() == 0){
  37. conditionRead.await();
  38. System.out.print("the message buffer is empty now,start into wait()\n");
  39. }
  40. Thread.sleep(100);
  41. message = ((LinkedList<String>)messages).poll();
  42. System.out.print("get message:"+message+" success\n");
  43. conditionWrite.signalAll();
  44. }catch (InterruptedException e){
  45. e.printStackTrace();
  46. }finally {
  47. lock.unlock();
  48. }
  49. return message;
  50. }
  51. }
Modifier and TypeMethod and Description
void

lock()

获得锁

voidlockInterruptibly()

获取锁定,除非当前线程是 interrupted 。

ConditionnewCondition()

返回一个新Condition绑定到该实例Lock实例。

booleantryLock()

只有在调用时才可以获得锁。

booleantryLock(long time, TimeUnit unit)

如果在给定的等待时间内是空闲的,并且当前的线程尚未得到 interrupted,则获取该锁。

void

unlock();

释放锁

  1. package java.util.concurrent.locks;
  2. import java.util.concurrent.TimeUnit;
  3. public interface Lock {
  4. void lock();
  5. void lockInterruptibly() throws InterruptedException;
  6. boolean tryLock();
  7. boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  8. void unlock();
  9. Condition newCondition();
  10. }

 

  1. package java.util.concurrent.locks;
  2. import java.util.concurrent.TimeUnit;
  3. import java.util.Date;
  4. public interface Condition {
  5. void await() throws InterruptedException;
  6. void awaitUninterruptibly();
  7. long awaitNanos(long nanosTimeout) throws InterruptedException;
  8. boolean await(long time, TimeUnit unit) throws InterruptedException;
  9. boolean awaitUntil(Date deadline) throws InterruptedException;
  10. void signal();
  11. void signalAll();
  12. }

 

、代码举例

8.1Demo1(先演示一下锁的可重入性)

  1. package com.szh.lock;
  2. /**
  3. * 演示锁的可重入性
  4. */
  5. public class Test01 {
  6. public synchronized void metthod1() {
  7. System.out.println("同步方法1");
  8. //线程执行 metthod1() 方法,默认 this 作为锁对象,
  9. //在 metthod1() 方法中调用了 method2() 方法,注意当前线程还是持有 this 锁对象的
  10. //method2() 同步方法默认的锁对象也是 this 对象, 要执行 method2() 必须先获得 this 锁对象,
  11. //当前 this 对象被当前线程持有,可以 再次获得 this 对象, 这就是锁的可重入性.
  12. //假设锁不可重入的话,可能会造成死锁
  13. method2();
  14. }
  15. public synchronized void method2() {
  16. System.out.println("同步方法2");
  17. method3();
  18. }
  19. public synchronized void method3() {
  20. System.out.println("同步方法3");
  21. }
  22. public static void main(String[] args) {
  23. Test01 obj=new Test01();
  24. new Thread(new Runnable() {
  25. @Override
  26. public void run() {
  27. obj.metthod1();
  28. }
  29. }).start();
  30. }
  31. }

8.2Demo2(ReentrantLock的基本使用)

  1. package com.szh.lock;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * ReentrantLock 的基本使用
  6. */
  7. public class Test02 {
  8. //定义一个显示锁
  9. static Lock lock=new ReentrantLock();
  10. public static void method() {
  11. //先获得锁
  12. lock.lock();
  13. //for循环此时就是同步代码块
  14. for (int i = 0; i < 3; i++) {
  15. System.out.println(Thread.currentThread().getName() + " ---> " + i);
  16. }
  17. //释放锁
  18. lock.unlock();
  19. }
  20. public static void main(String[] args) {
  21. Runnable r=new Runnable() {
  22. @Override
  23. public void run() {
  24. method();
  25. }
  26. };
  27. //启动三个线程
  28. new Thread(r).start();
  29. new Thread(r).start();
  30. new Thread(r).start();
  31. }
  32. }

 

8.3Demo3(使用Lock锁同步不同方法中的代码块)

  1. package com.szh.lock;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * 使用 Lock 锁同步不同方法中的同步代码块
  6. */
  7. public class Test03 {
  8. //定义锁对象
  9. static Lock lock=new ReentrantLock();
  10. public static void method1() {
  11. //经常在 try 代码块中获得 Lock 锁, 在 finally 子句中释放锁
  12. try {
  13. lock.lock(); //获得锁
  14. System.out.println(Thread.currentThread().getName() + " ---method1--- " + System.currentTimeMillis());
  15. Thread.sleep(1000);
  16. System.out.println(Thread.currentThread().getName() + " ---method1--- " + System.currentTimeMillis());
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }finally {
  20. lock.unlock(); //释放锁
  21. }
  22. }
  23. public static void method2() {
  24. //经常在 try 代码块中获得 Lock 锁, 在 finally 子句中释放锁
  25. try {
  26. lock.lock(); //获得锁
  27. System.out.println(Thread.currentThread().getName() + " ---method2--- " + System.currentTimeMillis());
  28. Thread.sleep(1000);
  29. System.out.println(Thread.currentThread().getName() + " ---method2--- " + System.currentTimeMillis());
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }finally {
  33. lock.unlock(); //释放锁
  34. }
  35. }
  36. public static void main(String[] args) {
  37. Runnable r1=new Runnable() {
  38. @Override
  39. public void run() {
  40. method1();
  41. }
  42. };
  43. Runnable r2=new Runnable() {
  44. @Override
  45. public void run() {
  46. method2();
  47. }
  48. };
  49. new Thread(r1).start();
  50. new Thread(r1).start();
  51. new Thread(r2).start();
  52. new Thread(r2).start();
  53. }
  54. }

 

8.4Demo4(ReentrantLock锁的可重入性) 

  1. package com.szh.lock;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * ReentrantLock 锁的可重入性
  6. */
  7. public class Test04 {
  8. static class SubThread extends Thread {
  9. //定义锁对象
  10. private static Lock lock=new ReentrantLock();
  11. //定义变量
  12. private static int num=0;
  13. @Override
  14. public void run() {
  15. for (int i = 0; i < 10000; i++) {
  16. try {
  17. //可重入锁指可以反复获得该锁
  18. lock.lock();
  19. lock.lock();
  20. num++;
  21. }finally {
  22. lock.unlock();
  23. lock.unlock();
  24. }
  25. }
  26. }
  27. }
  28. public static void main(String[] args) throws InterruptedException {
  29. SubThread t1=new SubThread();
  30. SubThread t2=new SubThread();
  31. t1.start();
  32. t2.start();
  33. t1.join();
  34. t2.join();
  35. System.out.println(SubThread.num);
  36. }
  37. }

 

8.5Demo5(ReentrantLock的lockInterruptibly()方法)

  1. package com.szh.lock;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * lockInterruptibly()方法
  6. * 如果当前线程未被中断则获得锁,
  7. * 如果当前线程被中断则出现异常.
  8. */
  9. public class Test05 {
  10. static class Service {
  11. private Lock lock=new ReentrantLock(); //定义锁对象
  12. public void serviceMethod() {
  13. try {
  14. //lock.lock(); 获得锁, 即使调用了线程的 interrupt() 方法, 也没有真正的中断线程
  15. //如果线程被中断了, 不会获得锁, 会产生异常
  16. lock.lockInterruptibly();
  17. System.out.println(Thread.currentThread().getName() + " --- begin lock");
  18. //执行一段耗时的操作
  19. for (int i = 0; i < Integer.MAX_VALUE; i++) {
  20. new StringBuilder();
  21. }
  22. System.out.println(Thread.currentThread().getName() + " --- end lock");
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. } finally {
  26. System.out.println(Thread.currentThread().getName() + " === 释放锁");
  27. lock.unlock(); //释放锁
  28. }
  29. }
  30. }
  31. public static void main(String[] args) throws InterruptedException {
  32. Service s=new Service();
  33. Runnable r=new Runnable() {
  34. @Override
  35. public void run() {
  36. s.serviceMethod();
  37. }
  38. };
  39. Thread t1=new Thread(r);
  40. t1.start();
  41. Thread.sleep(50);
  42. Thread t2=new Thread(r);
  43. t2.start();
  44. Thread.sleep(50);
  45. t2.interrupt(); //中断 t2 线程
  46. }
  47. }

 

 8.6Demo6(lockInterruptibly()方法可以避免死锁) 

  1. package com.szh.lock;
  2. import java.util.concurrent.locks.ReentrantLock;
  3. /**
  4. * 通过 ReentrantLock 锁的 lockInterruptibly() 方法避免死锁的产生
  5. */
  6. public class Test06 {
  7. static class MyLock implements Runnable {
  8. //创建两个ReentrantLock等锁对象
  9. private static ReentrantLock lock1=new ReentrantLock();
  10. private static ReentrantLock lock2=new ReentrantLock();
  11. int lockNum; //定义整数变量,决定使用哪个锁,偶数用lock1,奇数用lock2
  12. public MyLock(int lockNum) {
  13. this.lockNum=lockNum;
  14. }
  15. @Override
  16. public void run() {
  17. try {
  18. if (lockNum % 2 == 1) { //奇数, 先锁 1, 再锁 2
  19. lock1.lockInterruptibly();
  20. System.out.println(Thread.currentThread().getName() + "获得锁1,还需要获得锁2");
  21. Thread.sleep(1000);
  22. lock2.lockInterruptibly();
  23. System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2");
  24. }else { //偶数, 先锁 2, 再锁 1
  25. lock2.lockInterruptibly();
  26. System.out.println(Thread.currentThread().getName() + "获得了锁2,还需要获得锁1");
  27. Thread.sleep(1000);
  28. lock1.lockInterruptibly();
  29. System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2");
  30. }
  31. }catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }finally {
  34. if (lock1.isHeldByCurrentThread()) { //判断当前线程是否持有该锁
  35. lock1.unlock();
  36. }
  37. if (lock2.isHeldByCurrentThread()) {
  38. lock2.unlock();
  39. }
  40. System.out.println(Thread.currentThread().getName() + "线程退出");
  41. }
  42. }
  43. }
  44. public static void main(String[] args) throws InterruptedException {
  45. MyLock myLock1=new MyLock(11);
  46. MyLock myLock2=new MyLock(22);
  47. Thread t1=new Thread(myLock1);
  48. Thread t2=new Thread(myLock2);
  49. t1.start();
  50. t2.start();
  51. //在 main 线程, 等待 3000 ms, 如果还有线程没有结束就中断该线程
  52. Thread.sleep(1000 * 3);
  53. //可以中断任何一个线程来解决死锁, t2 线程会放弃对锁 1 的申请, 同时释放锁 2, t1 线程会完成它的任务
  54. if (t2.isAlive()) {
  55. t2.interrupt();
  56. }
  57. }
  58. }

 8.7Demo7(ReentrantLock的tryLock(long time, TimeUnit unit)方法) 

  1. package com.szh.lock;
  2. import java.util.concurrent.TimeUnit;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * tryLock(long time, TimeUnit unit) 的作用在给定等待时长内,
  6. * 锁没有被另外的线程持有, 并且当前线程也没有被中断, 则获得该锁.
  7. * 通过该方法可以实现锁对象的限时等待.
  8. */
  9. public class Test07 {
  10. static class TimeLock implements Runnable {
  11. private static ReentrantLock lock=new ReentrantLock(); //定义锁对象
  12. @Override
  13. public void run() {
  14. try {
  15. //假设 t1 线程先持有锁, 完成任务需要 4 秒钟,
  16. //这个时候 t2 线程尝试获得锁, t2 线程在 3 秒内还没有获得锁的话, 那么它就不再等了,直接放弃
  17. if (lock.tryLock(3, TimeUnit.SECONDS)) {
  18. System.out.println(Thread.currentThread().getName() + "获得锁,执行耗时任务");
  19. Thread.sleep(1000 * 4);
  20. /*
  21. 假设 t1 线程先持有锁, 完成任务需要 2 秒钟
  22. 这个时候t2 线程尝试获得锁, t2 线程会一直尝试
  23. 在它约定尝试的 3 秒内可以获得锁对象
  24. */
  25. //Thread.sleep(1000 * 2);
  26. }else {
  27. System.out.println(Thread.currentThread().getName() + "没有获得锁");
  28. }
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. } finally {
  32. if (lock.isHeldByCurrentThread()) {
  33. lock.unlock();
  34. }
  35. }
  36. }
  37. }
  38. public static void main(String[] args) {
  39. TimeLock timeLock=new TimeLock();
  40. Thread t1=new Thread(timeLock);
  41. Thread t2=new Thread(timeLock);
  42. t1.setName("t1");
  43. t2.setName("t2");
  44. t1.start();
  45. t2.start();
  46. }
  47. }

 8.8Demo8(ReentrantLock的tryLock()方法)

  1. package com.szh.lock;
  2. import java.util.concurrent.locks.ReentrantLock;
  3. /**
  4. * tryLock() 当锁对象没有被其他线程持有的情况下, 才会获得该锁定
  5. */
  6. public class Test08 {
  7. static class Service {
  8. private ReentrantLock lock=new ReentrantLock();
  9. public void serviceMethod() {
  10. try {
  11. if (lock.tryLock()) {
  12. System.out.println(Thread.currentThread().getName() + "获得锁定");
  13. Thread.sleep(1000 * 3); //模拟执行任务的时长
  14. }else {
  15. System.out.println(Thread.currentThread().getName() + "没有获得锁定");
  16. }
  17. }catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }finally {
  20. if (lock.isHeldByCurrentThread()) {
  21. lock.unlock();
  22. }
  23. }
  24. }
  25. }
  26. public static void main(String[] args) throws InterruptedException {
  27. Service service=new Service();
  28. Runnable r=new Runnable() {
  29. @Override
  30. public void run() {
  31. service.serviceMethod();
  32. }
  33. };
  34. Thread t1=new Thread(r);
  35. t1.start();
  36. Thread.sleep(100);
  37. Thread t2=new Thread(r);
  38. t2.start();
  39. }
  40. }

8.9Demo9(tryLock()方法可以避免死锁)

  1. package com.szh.lock;
  2. import java.util.concurrent.locks.ReentrantLock;
  3. /**
  4. * 使用 tryLock() 可以避免死锁
  5. */
  6. public class Test09 {
  7. static class MyLock implements Runnable {
  8. private static ReentrantLock lock1=new ReentrantLock();
  9. private static ReentrantLock lock2=new ReentrantLock();
  10. private int lockNum;
  11. public MyLock(int lockNum) {
  12. this.lockNum=lockNum;
  13. }
  14. @Override
  15. public void run() {
  16. if (lockNum % 2 == 0) { //偶数先锁 1, 再锁 2
  17. while (true) {
  18. try {
  19. if (lock1.tryLock()) {
  20. System.out.println(Thread.currentThread().getName() + "获得了锁1,还想获得锁2");
  21. Thread.sleep(50);
  22. try {
  23. if (lock2.tryLock()) {
  24. System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2,完成任务了");
  25. return;
  26. }
  27. } finally {
  28. if (lock2.isHeldByCurrentThread()) {
  29. lock2.unlock();
  30. }
  31. }
  32. }
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. } finally {
  36. if (lock1.isHeldByCurrentThread()) {
  37. lock1.unlock();
  38. }
  39. }
  40. }
  41. }else { //奇数就先锁 2, 再锁 1
  42. while (true) {
  43. try {
  44. if (lock2.tryLock()) {
  45. System.out.println(Thread.currentThread().getName() + "获得了锁2,还想获得锁1");
  46. Thread.sleep(50);
  47. try {
  48. if (lock1.tryLock()) {
  49. System.out.println(Thread.currentThread().getName() + "同时获得了锁1与锁2,完成任务了");
  50. return;
  51. }
  52. } finally {
  53. if (lock1.isHeldByCurrentThread()) {
  54. lock1.unlock();
  55. }
  56. }
  57. }
  58. } catch (InterruptedException e) {
  59. e.printStackTrace();
  60. } finally {
  61. if (lock2.isHeldByCurrentThread()) {
  62. lock2.unlock();
  63. }
  64. }
  65. }
  66. }
  67. }
  68. }
  69. public static void main(String[] args) {
  70. MyLock lock1=new MyLock(11);
  71. MyLock lock2=new MyLock(22);
  72. Thread t1=new Thread(lock1);
  73. Thread t2=new Thread(lock2);
  74. t1.start();
  75. t2.start();
  76. //运行后, 使用 tryLock() 尝试获得锁, 不会傻傻的等待, 通过循环不停的再次尝试, 如果等待的时间足够长, 线程总是会获得想要的资源
  77. }
  78. }

 

 转:Java中的Lock详解_向上的狼的博客-CSDN博客_java lock

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号