一。ReentrantLock类的使用(同一个lock可以多个Condition)
1.作用:java多线程中,可以使用synchronized关键字来实现线程之间的同步互斥,JDK1.5中新增了ReentrantLock类也能达到同样的效果,并且
在扩展功能上也更加强大,比如具有嗅探锁定、多路分支通知等功能,使用上比synchronized更加的灵活。
2.简单使用示例(也是获取对象锁):
public class MyService {
private Lock lock = new ReentrantLock();
public void testMethod() {
lock.lock();
for (int i = 0; i < 5; i++) {
System.out.println("ThreadName=" + Thread.currentThread().getName()
+ (" " + (i + 1)));
}
lock.unlock();
}
}
public class MyThread extends Thread {
private MyService service;
public MyThread(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
MyThread a1 = new MyThread(service);
MyThread a2 = new MyThread(service);
MyThread a3 = new MyThread(service);
MyThread a4 = new MyThread(service);
MyThread a5 = new MyThread(service);
a1.start();
a2.start();
a3.start();
a4.start();
a5.start();
}
}
3.使用Condition实现等待/通知
关键字synchronized与wait()和notify()/notifyAll()方法结合可以实现等待/通知模式,类ReentrantLock也可以实现同样的功能,需要借助于Condition对象。
多路通知:不同于notifyAll()通知全部等待在对象锁上的线程,Condition可以实现多路通知,也就是一个lock对象里面可以创建多个Condition,
线程对象可以注册在指定的Condition中,从而可以有选择性的通知部分线程,在线程调度上更加灵活。
而synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都祖册在它一个对象的身上。
注意事项:使用condition.await()前也是要先获取对象锁,这里通过lock.lock()获取。
Object类中的wait()方法相当于Condition类中的await()方法
Object类中的wait(long timeout)方法相当于Condition类中的await(long time,TimeUnit unit)方法
Object类中的notify()方法相当于Condition类中的signal()方法
Object类中的notifyAll()方法相当于Condition类中的signalAll()方法
使用单个Condition实例:
public class MyService {
private Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
public void await() {
try {
lock.lock();
System.out.println(" await时间为" + System.currentTimeMillis());
condition.await();
System.out.println(" 被唤醒了" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signal() {
try {
lock.lock();
System.out.println("signal时间为" + System.currentTimeMillis());
condition.signal();
} finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.await();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.start();
Thread.sleep(3000);
service.signal();
}
}
使用多个Condition实例:
public class MyService {
private Lock lock = new ReentrantLock();
public Condition conditionA = lock.newCondition();
public Condition conditionB = lock.newCondition();
public void awaitA() {
try {
lock.lock();
System.out.println("begin awaitA时间为" + System.currentTimeMillis()
+ " ThreadName=" + Thread.currentThread().getName());
conditionA.await();
System.out.println(" end awaitA时间为" + System.currentTimeMillis()
+ " ThreadName=" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitB() {
try {
lock.lock();
System.out.println("begin awaitB时间为" + System.currentTimeMillis()
+ " ThreadName=" + Thread.currentThread().getName());
conditionB.await();
System.out.println(" end awaitB时间为" + System.currentTimeMillis()
+ " ThreadName=" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalAll_A() {
try {
lock.lock();
System.out.println(" signalAll_A时间为" + System.currentTimeMillis()
+ " ThreadName=" + Thread.currentThread().getName());
conditionA.signalAll();
} finally {
lock.unlock();
}
}
public void signalAll_B() {
try {
lock.lock();
System.out.println(" signalAll_B时间为" + System.currentTimeMillis()
+ " ThreadName=" + Thread.currentThread().getName());
conditionB.signalAll();
} finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.awaitA();
}
}
public class ThreadB extends Thread {
private MyService service;
public ThreadB(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.awaitB();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
Thread.sleep(3000);
service.signalAll_A();
}
}
4. 生产者/消费者中使用lock和Condition
一个生产者和一个消费者:和wait/notify完全类似,只不过synchronized关键字用lock.lock(),wait()用condition.await(),因为等待的线程只能是异类,
所以使用signal或signalAll效果一样,不会出现假死现象。
多个生产者和多个消费者:使用signal同样会出现假死现象,解决方法也是类似,使用signalAll即可,即保证通知的有异类去消费或生产,使逻辑能够继续下去。
5.公平锁与非公平锁:
公平锁:基本上按照线程的FIFO的顺序获得锁,先等待获取锁的线程基本上(不绝对)先获得锁。
非公平锁:抢占式的,无规律。
6.lock.getHoldConunt(): 查询当前线程保持此锁定的个数。
lock.getQueueLength():返回正等待获取此锁定的线程估计数。
lock.hasQueuedThread(Thread thread):查询指定的线程是否正在等待获取此锁定。
lock.hasQueuedThreads():查询是否有线程正在等待获取此锁定。
7.lock.hasWaiters(Condition condition):查询是否有正在等待与此锁的condition条件。
lock.getWaitQueueLength(Condition condition): 查询正在等待与此锁的condition条件的线程数。
8.lock.isFair():查询锁是否公平锁。
lock.isHeldByCurrentThread():查询当前线程是否保持此锁定。
lock.isLocked():查询此锁定是否由任意线程保持。
9.lock.lockInterruptibly():如果当前线程未被中断,则获取锁定(获取时如果其他线程占用锁也是需要等待的),如果已经被中断则出现异常。
lock.tryLock():尝试锁,如果未被其他线程占用,则获取该锁定。
lock.tryLock(long timeout,TimeUnit unit):如果锁在给定的等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。
实例代码:
public class MyService {
public ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void waitMethod() {
try {
lock.lockInterruptibly();
System.out.println("lock " + Thread.currentThread().getName());
for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
String newString = new String();
Math.random();
}
} catch (InterruptedException e) {
System.out.println("线程"+Thread.currentThread().getName()+"进入catch~!");
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
final MyService service = new MyService();
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();// 打中断标记,如果不打则B等待A执行完再执行,不会抛异常。
System.out.println("main end!");
}
}
10.condition.awaitUninterrupted():使线程等待且不影响对此线程的interrupt()方法调用。
示例代码:
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()则能响应中断且需要加上catch响应InterruptException异常
condition.awaitUninterruptibly();
System.out.println("wait end");
} finally {
lock.unlock();
}
}
}
public class MyThread extends Thread {
private Service service;
public MyThread(Service service) {
super();
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();
}
}
}
11.condition.awaitUntil(long time):等待到某个时间点,到期前是可以被其他线程用signal唤醒的。
示例代码:
public class MyService {
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();
}
}
}
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.waitMethod();
}
}
public class ThreadB extends Thread {
private MyService service;
public ThreadB(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.notifyMethod();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA myThreadA = new ThreadA(service);
myThreadA.start();
Thread.sleep(2000);
ThreadB myThreadB = new ThreadB(service);
myThreadB.start();
}
}
运行结果:
wait begin timer=1490940903168
notify begin timer=1490940905148
notify end timer=1490940905148
wait end timer=1490940905149
12.使用Condition实现顺序执行。
示例代码,通过volatile类型的nextPrintWho变量控制下一个该那种线程启动,通过多路通知将三种等待线程归类,分别通知:
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() {
public void run() {
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() {
public void run() {
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() {
public void run() {
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();
}
}
}
二。ReentrantReadWriteLock类的使用(分别控制读写方法的lock)
1.作用:ReentrantLock具有完全互斥排他的效果,同一时间只有一个线程在执行lock()方法后面的任务,而ReentrantReadWriteLock类是一种读写锁
使用它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁来提升该方法的代码运行速度。
2.ReentrantReadWriteLock有两个锁,一个是读操作相关锁(共享锁),一个是写操作相关锁(排他锁),读写互斥、写写互斥,读读不互斥。
3.读写互斥实例代码:
public class MyService {
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) {
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) {
e.printStackTrace();
}
}
}
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.read();
}
}
public class ThreadB extends Thread {
private MyService service;
public ThreadB(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.write();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
Thread.sleep(1000);
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
}
}