Java中的互斥锁,了解一下...

Posted Goach的开发日记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的互斥锁,了解一下...相关的知识,希望对你有一定的参考价值。

在 Java 的世界里面,我们平时使用最多的就是 synchronized 。但在 Java 里面还有一种互斥锁,它是通过 ReentrantLock 来实现的。那么什么是互斥锁呢,先来看一个例子。


开启三个线程,它们的 ID 分别为 ABC。然后依次轮训打印他们的 ID 。这样来回打印 10 次

这是一个面试题目,如果通过 synchronized 来实现的话,代码如下:


public class ThreadTest { public static void main(String[] args) {        Loop loop = new Loop(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) { loop.thread1(); } System.out.println("线程1退出"); } }, "A").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) { loop.thread2(); } System.out.println("线程2退出"); } }, "B").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) { loop.thread3(); } System.out.println("线程3退出"); } }, "C").start();
}
private static final class Loop { private static int num = 0; private final Object lock = new Object();
private void thread1() { synchronized (lock) { if (num == 1 || num == 2) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("线程1" + Thread.currentThread().getName()); num = 1; lock.notifyAll(); } } }
private void thread2() { synchronized (lock) { if (num == 0 || num == 2) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("线程2" + Thread.currentThread().getName()); num = 2; lock.notifyAll(); } } }
private void thread3() { synchronized (lock) { if (num == 0 || num == 1) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("线程3" + Thread.currentThread().getName()); num = 0; lock.notifyAll(); } } } } }


虽然能基本上实现,但是当一个线程通知其他线程的时候,其他两个线程会同时去抢这个锁,没法指定一个线程获取当前锁。而互斥锁正好有这个特点,所以我们就可以通过互斥锁来实现。


public class ThreadTest { public static void main(String[] args) { Loop2 loop = new Loop2(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) { loop.thread1(); } System.out.println("线程1退出"); } }, "A").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) { loop.thread2(); } System.out.println("线程2退出"); } }, "B").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) { loop.thread3(); } System.out.println("线程3退出"); } }, "C").start();
    } /** * 互斥锁 */ private static final class Loop2 { private static int num = 0; private final Lock lock = new ReentrantLock(); private final Condition tread1Condition = lock.newCondition(); private final Condition tread2Condition = lock.newCondition(); private final Condition tread3Condition = lock.newCondition();
private void thread1() { lock.lock(); try { if (num != 0) { tread1Condition.await(); } System.out.println("线程1" + Thread.currentThread().getName()); num = 1; tread2Condition.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }
private void thread2() { lock.lock(); try { if (num != 1) { tread2Condition.await(); } System.out.println("线程2" + Thread.currentThread().getName()); num = 2; tread3Condition.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }
private void thread3() { lock.lock(); try { if(num != 2){ tread3Condition.await(); } System.out.println("线程3" + Thread.currentThread().getName()); num = 0; tread1Condition.signal(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } }}


上面的 Condition 是 ReentrantLock 的一个约束条件,它包括 await , sigal 等方法来指定某个线程获取锁。


总结


  1. 互斥锁可以指定某个线程获取锁,并同步

  2. 互斥锁是通过 ReentrantLock + Condition 来实现的

  3. 互斥锁一般有 await 和 signal 等方法来通信

以上是关于Java中的互斥锁,了解一下...的主要内容,如果未能解决你的问题,请参考以下文章

简明笔记:用同步与互斥锁,讲“美食争夺”。

java并发线程锁技术的使用

java中ReentrantReadWriteLock读写锁的使用

互斥锁 & 共享锁

轻松搞懂Java中的自旋锁

ReentrantReadWriteLock场景应用