文章目录
- 4.1 使用 ReentrantLock 类
- 4.1.10 方法 getHoldCount()、getQueueLength() 和 getWaitQueueLength() 的测试
- 4.1.11 方法 hasQueuedThread()、hasQueuedThreads() 和 hasWaiters() 的测试
- 4.1.12 方法 isFair()、isHeldByCurrentThread() 和 isLocked() 的测试
- 4.1.13 方法 lockInterruptibly()、tryLock() 和 tryLock(long timeout,TimeUnit unit) 的测试
- 4.1.14 方法 awitUniterruptibly() 的使用
- 4.1.15 方法 awaitUntil() 的使用
- 4.1.16 使用 Condition 实现顺序执行
- 4.2 使用 ReentrantReadWriteLock 类
- 4.3 本章总结
声明:
本博客是本人在学习《Java 多线程编程核心技术》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。
本博客已标明出处,如有侵权请告知,马上删除。
4.1 使用 ReentrantLock 类
4.1.10 方法 getHoldCount()、getQueueLength() 和 getWaitQueueLength() 的测试
getHoldCount()
方法 int getHoldCount() 的作用是查询当前线程保持此锁定的个数,也就是调用 lock() 方法的次数。
-
创建公共类
public class Service { private ReentrantLock lock = new ReentrantLock(); public void serviceMethod1() { try { lock.lock(); System.out.println("serviceMethod1 getHoldCount = " + lock.getHoldCount()); serviceMethod2(); }finally { lock.unlock(); } } public void serviceMethod2() { try { lock.lock(); System.out.println("serviceMethod2 getHoldCount = " + lock.getHoldCount()); }finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) { // getiHoldCount的作用是查询当前线程保持此锁定的个数,也就是调用lock()方法次数。 Service service = new Service(); service.serviceMethod1(); } }
运行结果:
serviceMethod1 getHoldCount = 1 serviceMethod2 getHoldCount = 2
getQueueLength()
方法 int getQueueLength() 的作用是返回正等待获取此锁定的线程估计数。比如有 5 个线程,1 个线程首先执行 await() 方法,那么在调用 getQueueLength() 方法后返回值是 4,说明有 4 个线程同时再等待 lock 的释放。
-
创建公共类
public class Service { public ReentrantLock lock = new ReentrantLock(); public void serviceMethod1() { try { lock.lock(); System.out.println("Thread name = " + Thread.currentThread().getName() + " in"); Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.serviceMethod1(); } }; Thread[] thread = new Thread[10]; for (int i = 0; i < 10; i++) { thread[i] = new Thread(runnable); } for (int i = 0; i < 10; i++) { thread[i].start(); } Thread.sleep(2000); System.out.println(service.lock.getQueueLength() + " processes is waiting!"); } }
运行结果:
Thread name = Thread-0 in 9 processes is waiting!
getWaitQueueLength
方法 int getWaitQueueLength(Condition condition) 的作用是返回等待与此锁定相关的给定条件 Condition 的线程估计数,比如 5 个线程,每个线程都执行了同一个 condition 对象的 await() 方法,则调用 getWaitQueueLength(Condition condition) 方法时返回的 int 值是 5 。
-
创建公共类
public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition newCondition = lock.newCondition(); public void waitMethod() { try { lock.lock(); newCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void notifyMethod() { try { lock.lock(); System.out.println("有 " + lock.getWaitQueueLength(newCondition) + " 个线程正在等待newCondition"); newCondition.signal(); } finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread[] threads = new Thread[10]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(runnable); } for (int i = 0; i < threads.length; i++) { threads[i].start(); } Thread.sleep(2000); service.notifyMethod(); } }
运行结果:
有 10 个线程正在等待newCondition
4.1.11 方法 hasQueuedThread()、hasQueuedThreads() 和 hasWaiters() 的测试
hasQueuedThread
-
方法 boolean hasQueuedThread(Thread thread) 的作用是查询指定的线程是否正在等待获取此锁定。
-
方法 boolean hasQueuedThreads() 的作用是查询是否有线程正在等待获取此锁定。
-
创建公共类
public class Service { public ReentrantLock lock = new ReentrantLock(); public Condition newCondition = lock.newCondition(); public void waitMethod() { try { lock.lock(); Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread threadA = new Thread(runnable); threadA.start(); Thread.sleep(500); Thread threadB = new Thread(runnable); threadB.start(); Thread.sleep(500); /** * hasQueuedThread(thread)查询知道这个的线程是否正在等待获取此lock * hasQueuedThreads()则是查询是否有线程正在等待获取此lock */ System.out.println(service.lock.hasQueuedThread(threadA)); System.out.println(service.lock.hasQueuedThread(threadB)); System.out.println(service.lock.hasQueuedThreads()); } }
运行结果:
false true true
hasWaiters
方法 boolean hasWaiters(Condition condition) 的作用是查询是否有线程正在等待与此锁定有关的 condition 条件。
-
创建公共类
public class Service { public ReentrantLock lock = new ReentrantLock(); public Condition newCondition = lock.newCondition(); public void waitMethod() { try { lock.lock(); newCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void notifyMethod() { try { lock.lock(); System.out.println("有没有线程正在等待newCondition? " + lock.hasWaiters(newCondition) + " 线程数是多少? " + lock.getWaitQueueLength(newCondition)); newCondition.signal(); } finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread[] threads = new Thread[10]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(runnable); } for (int i = 0; i < threads.length; i++) { threads[i].start(); } Thread.sleep(2000); service.notifyMethod(); } }
运行结果:
有没有线程正在等待newCondition? true 线程数是多少? 10
4.1.12 方法 isFair()、isHeldByCurrentThread() 和 isLocked() 的测试
isFair()
方法 boolean isFair() 的作用是判断是不是公平锁。在默认的情况下,ReentrantLock 类使用的是非公平锁。
-
创建公共类
public class Service { private ReentrantLock lock = new ReentrantLock(); public Service(boolean isFair) { lock = new ReentrantLock(isFair); } public void serviceMethod() { try { lock.lock(); System.out.println("公平锁的情况: " + lock.isFair()); } finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) { final Service service1 = new Service(true); final Service service2 = new Service(false); Runnable runnable1 = new Runnable() { @Override public void run() { service1.serviceMethod(); } }; Runnable runnable2 = new Runnable() { @Override public void run() { service2.serviceMethod(); } }; //ReentrantLock 默认是非公平锁 Thread t1 = new Thread(runnable1); Thread t2 = new Thread(runnable2); t1.start(); t2.start(); } }
运行结果:
公平锁的情况: true 公平锁的情况: false
isHeldByCurrentThread()
方法 boolean isHeldByCurrentThread() 的作用是查询当前线程是否保持此锁定。
-
创建公共类
public class Service { private ReentrantLock lock; public Service(boolean isFair) { lock = new ReentrantLock(isFair); } public void serviceMethod() { try { System.out.println(lock.isHeldByCurrentThread()); lock.lock(); System.out.println(lock.isHeldByCurrentThread()); } finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) { final Service service1 = new Service(true); Runnable runnable = new Runnable() { @Override public void run() { service1.serviceMethod(); } }; Thread thread = new Thread(runnable); //isHeldByCurrentThread 是查看当前线程是否保持此锁定。 thread.start(); } }
运行结果:
false true
isLocked()
方法 boolean isLocked() 的作用是查询此锁定是否由任意线程保持。
-
创建公共类
public class Service { private ReentrantLock lock; public Service(boolean isFair) { super(); lock = new ReentrantLock(isFair); } public void serviceMethod() { try { System.out.println(lock.isLocked()); lock.lock(); System.out.println(lock.isLocked()); } finally { lock.unlock(); } } }
-
测试类
public class Run { public static void main(String[] args) { final Service service1 = new Service(true); Runnable runnable = new Runnable() { @Override public void run() { service1.serviceMethod(); } }; Thread thread = new Thread(runnable); //isLocked作用是查询此锁定是否由任意线程保持 thread.start(); } }
运行结果:
false true
4.1.13 方法 lockInterruptibly()、tryLock() 和 tryLock(long timeout,TimeUnit unit) 的测试
lockInterruptibly()
方法 void lockInterruptibly() 的作用是:如果当前线程未被中断,则获取锁定,如果已经被中断,则出现异常。
-
创建公共类
public class Service { public ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void waitMethod(){ try { lock.lock(); System.out.println("lock begin " + Thread.currentThread().getName()); for (int i = 0; i < Integer.MAX_VALUE / 10; i++) { String newString = ""; Math.random(); } System.out.println("lock end " + Thread.currentThread().getName()); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }
-
测试类
public class Run { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnableRef = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread threadA = new Thread(runnableRef); threadA.setName("A"); threadA.start(); Thread.sleep(500); Thread threadB = new Thread(runnableRef); threadB.setName("B"); threadB.start(); threadB.interrupt(); // 打标记 System.out.println("main end!"); } }
运行结果:
lock begin A main end! lock end A lock begin B lock end B
没有出现异常,A、B 线程正常结束,按钮变灰。
前面实验使用的是 Lock() 方法,说明线程 B 被 interrupt 中断了,那么执行 lock() 则不出现异常,正常执行。
-
将类 Service.java 中原有代码 “lock.lock()” 变成 “lock.lockInterruptibly()”,运行结果如下
lock begin A java.lang.InterruptedException at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335) at rt9.Service.waitMethod(Service.java:12) at rt9.Run$1.run(Run.java:9) at java.lang.Thread.run(Thread.java:745) main end! lock end A
tryLock()
方法 boolean tryLock() 的作用是,仅在调用时锁定未被另一个线程保持的情况下,才获得该锁定。
-
创建公共类
public class Service { public ReentrantLock lock = new ReentrantLock(); public void waitMethod() { if (lock.tryLock()) { System.out.println(Thread.currentThread().getName() + "获得锁"); } else { System.out.println(Thread.currentThread().getName() + "没有获得锁"); } } }
-
测试类
public class Run { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnableRef = new Runnable() { @Override public void run() { service.waitMethod(); } }; //tryLock没有参数时 仅在调用时锁定未被另一个线程保持的情况下,才或得该锁定。 Thread threadA = new Thread(runnableRef); threadA.setName("A"); threadA.start(); Thread threadB = new Thread(runnableRef); threadB.setName("B"); threadB.start(); } }
运行结果:
A获得锁 B没有获得锁
tryLock(long timeout, TimeUnit unit)
方法 boolean tryLock(long timeout,TimeUnit unit) 的作用是,如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。
-
创建公共类
public class Service { public ReentrantLock lock = new ReentrantLock(); public void waitMethod() { try { //如果3秒没有锁没有被其他线程保持,并且当前线程没有中断就或得锁定 if (lock.tryLock(3, TimeUnit.SECONDS)) { System.out.println(" " + Thread.currentThread().getName() + "获得锁的时间:" + System.currentTimeMillis()); Thread.sleep(10000); } else { System.out.println(" " + Thread.currentThread().getName() + "没有获得锁"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }
-
测试类
public class Run { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnableRef = () -> { System.out.println(Thread.currentThread().getName() + "调用waitMethod时间:" + System.currentTimeMillis()); service.waitMethod(); }; Thread threadA = new Thread(runnableRef); threadA.setName("A"); threadA.start(); Thread.sleep(500); Thread threadB = new Thread(runnableRef); threadB.setName("B"); threadB.start(); } }
运行结果:
A调用waitMethod时间:1608024376272 A获得锁的时间:1608024376274 B调用waitMethod时间:1608024376772 B没有获得锁
4.1.14 方法 awitUniterruptibly() 的使用
当调用了 thread.interrupt() 方法之后,condition.await() 方法会报异常,但是调用 awaitUniterruptibly() 方法不会报异常。
-
创建公共类
public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void testMethod() { try { lock.lock(); System.out.println("wait begin"); condition.await(); System.out.println("wait end"); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("catch"); } finally { lock.unlock(); } } }
-
创建自定义线程类
public class MyThread extends Thread { private Service service; public MyThread(Service service) { this.service = service; } @Override public void run() { service.testMethod(); } }
-
测试类
public class Run { public static void main(String[] args) { try { Service service = new Service(); MyThread myThread = new MyThread(service); myThread.start(); Thread.sleep(3000); myThread.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果:
wait begin catch java.lang.InterruptedException at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048) at rt12.Service.testMethod(Service.java:14) at rt12.MyThread.run(MyThread.java:12)
程序运行后出现异常,这是正常现象。
-
更改 Service.java 类,修改 condition.await() 为 condition.awaitUninterruptibly()
public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void testMethod() { try { lock.lock(); System.out.println("wait begin"); condition.awaitUninterruptibly(); System.out.println("wait end"); } finally { lock.unlock(); } } }
运行结果:
wait begin
4.1.15 方法 awaitUntil() 的使用
调用 awaitUntil(long time) 是等待 time 时间后自动唤醒。
-
创建公共类
public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void waitMethod() { try { Calendar calendarRef = Calendar.getInstance(); calendarRef.add(Calendar.SECOND, 10); lock.lock(); System.out.println("wait begin timer=" + System.currentTimeMillis()); condition.awaitUntil(calendarRef.getTime()); System.out.println("wait end timer=" + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void notifyMethod() { try { Calendar calendarRef = Calendar.getInstance(); calendarRef.add(Calendar.SECOND, 10); lock.lock(); System.out.println("notify begin timer=" + System.currentTimeMillis()); condition.signalAll(); System.out.println("notify end timer=" + System.currentTimeMillis()); } finally { lock.unlock(); } } }
-
创建 2 个自定义线程类
public class MyThreadA extends Thread { private Service service; public MyThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.waitMethod(); } }
public class MyThreadB extends Thread { private Service service; public MyThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.notifyMethod(); } }
-
测试类
public class Run1 { public static void main(String[] args){ Service service = new Service(); MyThreadA myThreadA = new MyThreadA(service); myThreadA.start(); } }
运行结果:
wait begin timer=1608027202380 wait end timer=1608027212365
-
测试类2
public class Run2 { public static void main(String[] args) throws InterruptedException { Service service = new Service(); MyThreadA myThreadA = new MyThreadA(service); MyThreadB myThreadB = new MyThreadB(service); myThreadA.start(); Thread.sleep(2000); myThreadB.start(); } }
运行结果:
wait begin timer=1608027571582 notify begin timer=1608027573553 notify end timer=1608027573553 wait end timer=1608027573553
说明线程在等待时间到达前,可以被其他线程提前唤醒。
4.1.16 使用 Condition 实现顺序执行
使用 Condition 对象可以对线程执行的业务进行排序规划。
测试类:
public class Run {
volatile private static int nextPrintWho = 1;
private static ReentrantLock lock = new ReentrantLock();
final private static Condition conditionA = lock.newCondition();
final private static Condition conditionB = lock.newCondition();
final private static Condition conditionC = lock.newCondition();
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
try {
lock.lock();
while (nextPrintWho != 1) {
conditionA.await();
}
for (int i = 0; i < 3; i++) {
System.out.println("ThreadA " + (i + 1));
}
nextPrintWho = 2;
conditionB.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
Thread threadB = new Thread(() -> {
try {
lock.lock();
while (nextPrintWho != 2) {
conditionB.await();
}
for (int i = 0; i < 3; i++) {
System.out.println("ThreadB " + (i + 1));
}
nextPrintWho = 3;
conditionC.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
Thread threadC = new Thread(() -> {
try {
lock.lock();
while (nextPrintWho != 3) {
conditionC.await();
}
for (int i = 0; i < 3; i++) {
System.out.println("ThreadC " + (i + 1));
}
nextPrintWho = 1;
conditionA.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
Thread[] aArray = new Thread[5];
Thread[] bArray = new Thread[5];
Thread[] cArray = new Thread[5];
for (int i = 0; i < 5; i++) {
aArray[i] = new Thread(threadA);
bArray[i] = new Thread(threadB);
cArray[i] = new Thread(threadC);
aArray[i].start();
bArray[i].start();
cArray[i].start();
}
}
}
运行结果:
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
4.2 使用 ReentrantReadWriteLock 类
类 ReentrantLock 具有完全互斥排他的效果,即同一时间只有一个线程在执行 ReentrantLock.lock() 方法后面的任务。这样做虽然保证了实例变量的线程安全性,但效率却是非常低下的。所以在 JDK 中提供了一种读写锁 ReentrantReadWriteLock 类,使用它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁 ReentrantReadWriteLock 来提升该方法的代码运行速度。
读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。在没有线程 Thread 进行写入操作时,进行读取操作的多个 Thread 都可以获取读锁,而进入写入操作的 Thread 只有在获取写锁后才能进行写入操作。即多个 Thread 可以同时进行读取操作,但是同一时刻只允许一个 Thread 进行写入操作。
4.2.1 类 ReentrantReadWriteLock 的使用:读读共享
-
创建公共类
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { try { lock.readLock().lock(); System.out.println("获得读锁" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.readLock().unlock(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
创建 2 个自定义线程类
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.read(); } }
public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.read(); } }
-
测试类
public class Run { public static void main(String[] args) { Service service = new Service(); ThreadA a = new ThreadA(service); ThreadB b = new ThreadB(service); b.setName("B"); a.setName("A"); b.start(); a.start(); } }
运行结果:
获得读锁B 1608031685984 获得读锁A 1608031685984
从控制台中打印的时间来看,两个线程几乎同时进入 lock() 方法后面的代码。说明在此使用了 lock.readLock() 读锁可以提高程序运行效率,允许多个线程同时执行 lock() 方法后面的代码。
4.2.2 类 ReentrantReadWriteLock 的使用:写写互斥
-
修改公共类
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { try { lock.writeLock().lock(); System.out.println("获得写锁" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.writeLock().unlock(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
运行结果
获得写锁B 1608030877595 获得写锁A 1608030887596
使用写锁代码 lockwrieLock() 的效果就是同一时间只允许一个线程执行 lock() 方法后面的代码。
4.2.3 类 ReentrantReadWriteLock 的使用:读写互斥
-
创建公共类
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { try { lock.readLock().lock(); System.out.println("获得读锁" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.readLock().unlock(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void write() { try { try { lock.writeLock().lock(); System.out.println("获得写锁" + Thread.currentThread().getName() + " " + System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.writeLock().unlock(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
创建 2 个自定义线程类
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.read(); } }
public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.write(); } }
-
测试类
public class Run { public static void main(String[] args) { try { Service service = new Service(); ThreadA a = new ThreadA(service); ThreadB b = new ThreadB(service); a.setName("A"); b.setName("B"); a.start(); Thread.sleep(1000); b.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果:
获得读锁A 1608032477712 获得写锁B 1608032487712
此实验说明 “读写” 操作是互斥的,而且下一个示例说明 “写读” 操作也是互斥的。
即只要出现“写操作”的过程,就是互斥的。
4.2.4 类 ReentrantReadWriteLock 的使用:写读互斥
-
修改测试类
public class Run { public static void main(String[] args) { try { Service service = new Service(); ThreadA a = new ThreadA(service); ThreadB b = new ThreadB(service); a.setName("A"); b.setName("B"); b.start(); Thread.sleep(1000); a.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
-
运行结果
获得写锁B 1608032791225 获得读锁A 1608032801225
从控制台中打印的结果来看,“写读” 操作也是互斥的。
“读写”、“写读” 和 “写写” 都是互斥的;而 “读读” 是异步的,非互斥的。
4.3 本章总结
本章的学习已经完毕,在本章中完全可以使用 Lock 对象将 synchronized 关键字替换掉,而且其具有的独特功能也是 synchronized 所不具有的。在学习并发时,Lock 是 synchronized 关键字的进阶,掌握 Lock 有助于学习并发包中源代码的实现原理,在并发包中大量的类使用了 Lock 接口作为同步的处理方式。