1. ReentrantLock 类
1.1 使用 ReentrantLock 实现同步
public class Service {
private Lock lock = new ReentrantLock();
public void testA() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " testA begin time=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " testA begin time=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void testB() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " testB begin time=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " testB begin time=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
this.service = service;
}
@Override
public void run() {
service.testA();
}
}
public class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
this.service = service;
}
@Override
public void run() {
service.testB();
}
}
public class Test {
public static void main(String[] args) {
Service service = new Service();
ThreadA a = new ThreadA(service);
a.setName("Thread-A");
ThreadA aa = new ThreadA(service);
aa.setName("Thread-AA");
ThreadB b = new ThreadB(service);
b.setName("Thread-B");
ThreadB bb = new ThreadB(service);
bb.setName("Thread-BB");
a.start();
aa.start();
b.start();
bb.start();
}
}
1.2 使用 Condition 实现等待/通知模式
使用 ReentrantLock 结合 Condition 可以实现“选择性通知”,也就是一个 Lock 对象里可以创建多个 Condition (即对象监视器)实例,线程对象可以注册在指定的 Condition 中,从而可以有选择性的进行线程通知
public class Service {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void await() {
try {
lock.lock();
System.out.println("await begin time=" + System.currentTimeMillis());
condition.await();
System.out.println("await end time=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signal() {
try {
lock.lock();
System.out.println("signal begin time=" + System.currentTimeMillis());
condition.signal();
System.out.println("signal end time=" + System.currentTimeMillis());
} finally {
lock.unlock();
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
final Service service = new Service();
Runnable run1 = new Runnable() {
@Override
public void run() {
service.await();
}
};
Thread a = new Thread(run1);
a.start();
Thread.sleep(3000);
service.signal();
}
}
- Object 类中的
wait()方法相当于 Condition 类中的await()方法 - Object 类中的
wait(long timeout)方法相当于 Condition 类中的await(long time, TimeUnit unit)方法 - Object 类中的
noytify()方法相当于 Condition 类中的signal()方法 - Object 类中的
noytifyAll()方法相当于 Condition 类中的signalAll()方法
1.3 使用多个 Condition 实现通知部分线程
public class Service {
private ReentrantLock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
public void awaitA() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " awaitA begin time=" + System.currentTimeMillis());
conditionA.await();
System.out.println(Thread.currentThread().getName() + " awaitA end time=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitB() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " awaitB begin time=" + System.currentTimeMillis());
conditionB.await();
System.out.println(Thread.currentThread().getName() + " awaitB end time=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalAllA() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " signalAllA begin time=" + System.currentTimeMillis());
conditionA.signalAll();
System.out.println(Thread.currentThread().getName() + " signalAllA end time=" + System.currentTimeMillis());
} finally {
lock.unlock();
}
}
public void signalAllB() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " signalAllB begin time=" + System.currentTimeMillis());
conditionB.signalAll();
System.out.println(Thread.currentThread().getName() + " signalAllB end time=" + System.currentTimeMillis());
} finally {
lock.unlock();
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
final Service service = new Service();
Runnable run1 = new Runnable() {
@Override
public void run() {
service.awaitA();
}
};
Runnable run2 = new Runnable() {
@Override
public void run() {
service.awaitB();
}
};
Thread a = new Thread(run1);
Thread b = new Thread(run2);
a.start();
b.start();
Thread.sleep(5000);
service.signalAllA();
// service.signalAllB();
}
}
1.4 实现生产者/消费者模式(一对一)
public class Service {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set() {
try {
lock.lock();
if (hasValue) {
condition.await();
}
System.out.println(Thread.currentThread().getName() + " set");
hasValue = true;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get() {
try {
lock.lock();
if (!hasValue) {
condition.await();
}
System.out.println(Thread.currentThread().getName() + " get");
hasValue = false;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ConsumerThread extends Thread {
private Service service;
public ConsumerThread(Service service) {
this.service = service;
}
@Override
public void run() {
while (true) {
service.get();
}
}
}
public class ProducerThread extends Thread {
private Service service;
public ProducerThread(Service service) {
this.service = service;
}
@Override
public void run() {
while (true) {
service.set();
}
}
}
public class Test {
public static void main(String[] args) {
Service service = new Service();
ConsumerThread c = new ConsumerThread(service);
c.setName("Consumer");
ProducerThread p = new ProducerThread(service);
p.setName("Producer");
c.start();
p.start();
}
}
1.5 实现生产者/消费者模式(多对多)
public class Service {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set() {
try {
lock.lock();
while (hasValue) {
condition.await();
}
System.out.println(Thread.currentThread().getName() + " set");
hasValue = true;
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get() {
try {
lock.lock();
while (!hasValue) {
condition.await();
}
System.out.println(Thread.currentThread().getName() + " get");
hasValue = false;
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ConsumerThread extends Thread {
private Service service;
public ConsumerThread(Service service) {
this.service = service;
}
@Override
public void run() {
while (true) {
service.get();
}
}
}
public class ProducerThread extends Thread {
private Service service;
public ProducerThread(Service service) {
this.service = service;
}
@Override
public void run() {
while (true) {
service.set();
}
}
}
public class Test {
public static void main(String[] args) {
Service service = new Service();
ConsumerThread[] consumerThreads = new ConsumerThread[5];
ProducerThread[] producerThreads = new ProducerThread[5];
for (int i = 0;i < 5;i++) {
consumerThreads[i] = new ConsumerThread(service);
consumerThreads[i].setName("Consumer-" + i);
producerThreads[i] = new ProducerThread(service);
producerThreads[i].setName("Producer-" + i);
}
for (int i = 0;i < 5;i++) {
consumerThreads[i].start();
producerThreads[i].start();
}
}
}
1.6 公平锁和非公平锁
- 公平锁:公平锁表示线程获取锁的顺序是按照加锁的顺序来分配的,即先来先得的 FIFO 先进先出顺序
- 非公平锁:非公平锁是一种获取锁的抢占机制,是随机获取锁的,这种方式可能造成某些线程一直拿不到锁
public class MyThread extends Thread {
private ReentrantLock lock;
public MyThread(ReentrantLock lock) {
this.lock = lock;
}
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " get lock");
} finally {
lock.unlock();
}
}
}
public class Test {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock(true);
// ReentrantLock lock = new ReentrantLock(false);
MyThread[] myThreads = new MyThread[10];
for (int i = 0;i < 10;i++) {
myThreads[i] = new MyThread(lock);
}
for (int i = 0;i < 10;i++) {
myThreads[i].start();
}
}
}
1.7 getHoldCount()、getQueueLength()、getWaitQueueLength() 方法的使用
-
getHoldCount()方法:查询当前线程保持该锁的个数,也就是调用lock()方法的次数public class Service { private ReentrantLock lock = new ReentrantLock(); public void testA() { try { lock.lock(); System.out.println(Thread.currentThread().getName() + " testA() getHoldCount=" + lock.getHoldCount()); testB(); } finally { lock.unlock(); } } public void testB() { try { lock.lock(); System.out.println(Thread.currentThread().getName() + " testB() getHoldCount=" + lock.getHoldCount()); } finally { lock.unlock(); } } } public class Test { public static void main(String[] args) { Service service = new Service(); service.testA(); } } -
getQueueLength()方法:查询正在等待获取该锁的线程数(估计数)public class Service { public ReentrantLock lock = new ReentrantLock(); public void testA() { try { lock.lock(); Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public class Test { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.testA(); } }; Thread[] threads = new Thread[10]; for (int i = 0;i < 10;i++) { threads[i] = new Thread(runnable); } for (int i = 0;i < 10;i++) { threads[i].start(); } Thread.sleep(500); System.out.println("getQueueLength=" + service.lock.getQueueLength()); } } -
getWaitQueueLength(Condition condition)方法:查询等待该锁相关的 Condition 条件的线程数(估计数)public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void await() { try { lock.lock(); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signal() { try { lock.lock(); System.out.println("getWaitQueueLength=" + lock.getWaitQueueLength(condition)); condition.signal(); } finally { lock.unlock(); } } } public class Test { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.await(); } }; Thread[] threads = new Thread[10]; for (int i = 0;i < 10;i++) { threads[i] = new Thread(runnable); } for (int i = 0;i < 10;i++) { threads[i].start(); } Thread.sleep(500); service.signal(); service.signal(); service.signal(); } }
1.8 hasQueuedThread()、hasQueuedThreads()、hasWaiters() 方法的使用
-
hasQueuedThread(Thread thread)方法:判断指定线程是否等待该锁 -
hasQueuedThreads()方法:判断该锁是否有线程等待获取public class Service { public ReentrantLock lock = new ReentrantLock(); public void waitMethod() { try { lock.lock(); Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Test { public static void main(String[] args) { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread threadA = new Thread(runnable); Thread threadB = new Thread(runnable); threadA.start(); threadB.start(); System.out.println("threadA wait lock? " + service.lock.hasQueuedThread(threadA)); System.out.println("threadB wait lock? " + service.lock.hasQueuedThread(threadB)); System.out.println("have thread wait lock? " + service.lock.hasQueuedThreads()); } } -
hasWaiters(Condition condition)方法:判断是否有线程等待该锁相关的 Condition 条件public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void await() { try { lock.lock(); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signal() { try { lock.lock(); System.out.println("have thread wait lock condition? " + lock.hasWaiters(condition)); condition.signal(); } finally { lock.unlock(); } } } public class Test { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.await(); } }; Thread[] threads = new Thread[10]; for (int i = 0;i < 2;i++) { threads[i] = new Thread(runnable); } for (int i = 0;i < 2;i++) { threads[i].start(); } Thread.sleep(500); service.signal(); service.signal(); service.signal(); } }
1.9 isFair()、isHeldByCurrentThread()、lock.isLocked() 方法的使用
-
isFair()方法:判断是不是公平锁public class Service { private ReentrantLock lock; public Service(boolean isFair) { this.lock = new ReentrantLock(isFair); } public void testMethod() { try { lock.lock(); System.out.println("lock isFair=" + lock.isFair()); } finally { lock.unlock(); } } } public class Test { public static void main(String[] args) { // final Service service = new Service(false); final Service service = new Service(true); Runnable runnable = new Runnable() { @Override public void run() { service.testMethod(); } }; Thread thread = new Thread(runnable); thread.start(); } } -
isHeldByCurrentThread()方法:判断当前线程是否持有该锁public class Service { private ReentrantLock lock = new ReentrantLock(); public void testMethod() { try { System.out.println(Thread.currentThread().getName() + " held lock? " + lock.isHeldByCurrentThread()); lock.lock(); System.out.println(Thread.currentThread().getName() + " held lock? " + lock.isHeldByCurrentThread()); } finally { lock.unlock(); } } } public class Test { public static void main(String[] args) { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.testMethod(); } }; Thread thread = new Thread(runnable); thread.start(); } } -
lock.isLocked()方法:判断该锁是否被任意线程持有public class Service { private ReentrantLock lock = new ReentrantLock(); public void testA() { try { lock.lock(); Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void testB() { System.out.println("locked by any thread? " + lock.isLocked()); } } public class Test { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.testA(); } }; service.testB(); Thread thread = new Thread(runnable); thread.start(); Thread.sleep(50); service.testB(); } }
1.10 lockInterruptibly()、tryLock()、tryLock(long timeout, TimeUnit unit) 方法的使用
-
lockInterruptibly()方法:线程准备获取锁时,如果当前线程已被中断,则抛出异常public class Service { private ReentrantLock lock = new ReentrantLock(); public void testA() { try { lock.lockInterruptibly(); // lock.lock(); System.out.println("lock begin " + Thread.currentThread().getName()); for (int i = 0;i < Integer.MAX_VALUE / 10;i++) { Math.random(); } System.out.println("lock begin " + Thread.currentThread().getName()); } catch (InterruptedException e) { System.out.println("catch enter " + Thread.currentThread().getName()); e.printStackTrace(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } public class Test { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.testA(); } }; Thread a = new Thread(runnable); a.start(); Thread.sleep(500); Thread b = new Thread(runnable); b.start(); b.interrupt(); System.out.println("main end"); } } -
tryLock()方法:线程如果调用方法时锁未被另一个线程持有,则获取该锁public class Service { private ReentrantLock lock = new ReentrantLock(); public void testMethod() { if (lock.tryLock()) { System.out.println(Thread.currentThread().getName() + " get lock"); } else { System.out.println(Thread.currentThread().getName() + " not get lock"); } } } public class Test { public static void main(String[] args) { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.testMethod(); } }; Thread a = new Thread(runnable, "Thread-A"); Thread b = new Thread(runnable, "Thread-B"); a.start(); b.start(); } } -
tryLock(long timeout, TimeUnit unit) 方法:如果该锁在指定时间内没有被另一个线程持有,且当前线程未被中断,则获取该锁
public class Service { private ReentrantLock lock = new ReentrantLock(); public void testMethod() { try { if (lock.tryLock(3, TimeUnit.SECONDS)) { System.out.println(Thread.currentThread().getName() + " get lock"); Thread.sleep(5000); // Thread.sleep(2000); } else { System.out.println(Thread.currentThread().getName() + " not get lock"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } public class Test { public static void main(String[] args) { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.testMethod(); } }; Thread a = new Thread(runnable, "Thread-A"); Thread b = new Thread(runnable, "Thread-B"); a.start(); b.start(); } }
1.11 awaitUninterruptibly() 方法的使用
-
线程调用
await()方法后,此时再调用interrupt()方法抛出异常 -
线程调用
awaitUninterruptibly()方法后,此时再调用interrupt()方法不会抛出异常public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void testMethod() { try { lock.lock(); System.out.println("await begin"); // condition.await(); condition.awaitUninterruptibly(); System.out.println("await end"); } /*catch (InterruptedException e) { System.out.println("catch enter"); e.printStackTrace(); }*/ finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } public class Test { public static void main(String[] args) { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.testMethod(); } }; Thread a = new Thread(runnable); a.start(); a.interrupt(); } }
1.12 awaitUntil() 方法的使用
线程在指定时间内未被唤醒,则在指定时间后自动唤醒
public class Service {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void testMethod() {
try {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 5);
lock.lock();
System.out.println("await begin time=" + System.currentTimeMillis());
condition.awaitUntil(calendar.getTime());
System.out.println("await end time=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Test {
public static void main(String[] args) {
final Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.testMethod();
}
};
Thread a = new Thread(runnable);
a.start();
}
}
1.13 使用 Condition 实现顺序执行
public class Test {
private static ReentrantLock lock = new ReentrantLock();
private static Condition conditionA = lock.newCondition();
private static Condition conditionB = lock.newCondition();
private static Condition conditionC = lock.newCondition();
volatile private static int nextWho = 1;
public static void main(String[] args) {
Runnable runnable1 = new Runnable() {
@Override
public void run() {
try {
lock.lock();
while (nextWho != 1) {
conditionA.await();
}
System.out.println(Thread.currentThread().getName() + " run AAAAA");
nextWho = 2;
conditionB.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
};
Runnable runnable2 = new Runnable() {
@Override
public void run() {
try {
lock.lock();
while (nextWho != 2) {
conditionB.await();
}
System.out.println(Thread.currentThread().getName() + " run BBBBB");
nextWho = 3;
conditionC.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
};
Runnable runnable3 = new Runnable() {
@Override
public void run() {
try {
lock.lock();
while (nextWho != 3) {
conditionC.await();
}
System.out.println(Thread.currentThread().getName() + " run CCCCC");
nextWho = 1;
conditionA.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
};
Thread[] threadAs = new Thread[5];
Thread[] threadBs = new Thread[5];
Thread[] threadCs = new Thread[5];
for (int i = 0;i < 5;i++) {
threadAs[i] = new Thread(runnable1, "ThreadA-" + i);
threadBs[i] = new Thread(runnable2, "ThreadB-" + i);
threadCs[i] = new Thread(runnable3, "ThreadC-" + i);
}
for (int i = 0;i < 5;i++) {
threadAs[i].start();
threadBs[i].start();
threadCs[i].start();
}
}
}
2. ReentrantReadWriteLock 类
ReentrantReadWriteLock 读写锁有读锁(共享锁)和写锁(排它锁)。读锁之间不互斥,写锁之间互斥,读写锁之间互斥
2.1 读读共享
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void testMethod() {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " get readLock time=" + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
}
public class Test {
public static void main(String[] args) {
final Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.testMethod();
}
};
Thread a = new Thread(runnable, "Thread-A");
Thread b = new Thread(runnable, "Thread-B");
a.start();
b.start();
}
}
2.2 写写互斥
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void testMethod() {
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + " get writeLock time=" + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
}
public class Test {
public static void main(String[] args) {
final Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
service.testMethod();
}
};
Thread a = new Thread(runnable, "Thread-A");
Thread b = new Thread(runnable, "Thread-B");
a.start();
b.start();
}
}
2.3 读写互斥
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void readMethod() {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " get readLock time=" + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
public void writeMethod() {
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + " get writeLock time=" + System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
}
public class Test {
public static void main(String[] args) {
final Service service = new Service();
Runnable readRun = new Runnable() {
@Override
public void run() {
service.readMethod();
}
};
Runnable writeRun = new Runnable() {
@Override
public void run() {
service.writeMethod();
}
};
Thread a = new Thread(readRun, "Thread-A");
Thread b = new Thread(writeRun, "Thread-B");
a.start();
b.start();
}
}
学自《Java多线程编程核心技术》