java多线程编程核心技术4-Lock的使用

一。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(); 
}
}
  











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值