JAVA多线程-Lock的使用(一)-ReentrantLock与Condition

时间:2022-02-17 21:00:45

JAVA多线程-Lock的使用

      本节主要介绍使用Java5中的Lock对象也能实现同步的效果,而且在使用上更加方便。

一、使用ReentrantLock类

     在java多线程中,可以使用synchronized关键字来实现线程之间同步互斥,但在JDK1.5中新增加了ReentrantLock类也能达到同样的效果,并且在扩展功能上也更加强大,比如具有嗅探锁定多路分支通知等功能,并且在使用上也比synchronized更加的灵活。

     1.1 使用ReentrantLock实现同步:测试

package org.jksoft.thread.reentrantLock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 测试一:使用ReentrantLock去实习线程间的同步
* @author mcl
*
* 2016-2-21-上午11:11:46
*/
public class Test1 {
public static void main(String[] args) {
MyService service = new MyService();
for(int i =0;i<10;i++){
new ThreadA(service).start();
}
}
}
class ThreadA extends Thread{
private MyService service;
public ThreadA(MyService service){
this.service = service;
}
public void run(){
service.print();
}
}
class MyService{
private Lock lock = new ReentrantLock();
public void print(){
//获取锁
lock.lock();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+" : "+(i+1));
}
//释放锁
lock.unlock();
}
}
    结果: 

  JAVA多线程-Lock的使用(一)-ReentrantLock与Condition 

  分析: 我们可以看到,每个线程都是等待上一个线程打印完毕之后,才继续打印,因为当前线程已经持有锁,但线程之间打印的顺序是随机的。

  1.2 使用condition去实现等待/通知

package org.jksoft.thread.reentrantLock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 测试二:使用condition实现等待/通知 注意:wait与notify都是需要在同步代码块中调用,也就是必须持有当前锁
* 所以condition中的await()与signal()也同样必须持有当前锁
*
* @author mcl
*
* 2016-2-21-上午11:11:46
*/
public class Test2 {
public static void main(String[] args) {
MyService2 service = new MyService2();
ThreadB thread = new ThreadB(service );
thread.start();
try {
Thread.sleep(3000);
service.signal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ThreadB extends Thread{
private MyService2 service;
public ThreadB(MyService2 service){
this.service = service;
}
public void run(){
service.await();
}
}
class MyService2 {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void await() {
try {
lock.lock();
System.out.println("A");
condition.await();
System.out.println("B");

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("锁被释放了");
}
}
public void signal(){
try {
lock.lock();
condition.signal();

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
    结果: 线程B先执行await()等待通知,主线程睡3s后,调用service的signal()方法,唤醒处于waiting状态的线程B。

1.3 使用多个condition实现通知部分线程:

package org.jksoft.thread.reentrantLock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 测试三:使用多个condition实现线程部分通知
*
* @author mcl
*
* 2016-2-21-上午11:11:46
*/
public class Test3 {
public static void main(String[] args) {
MyService3 service = new MyService3();
ThreadC thread = new ThreadC(service );
thread.start();
ThreadD thread2 = new ThreadD(service );
thread2.start();
try {
Thread.sleep(3000);
service.Asignal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ThreadC extends Thread{
private MyService3 service;
public ThreadC(MyService3 service){
this.service = service;
}
public void run(){
service.Aawait();
}
}
class ThreadD extends Thread{
private MyService3 service;
public ThreadD(MyService3 service){
this.service = service;
}
public void run(){
service.Bawait();
}
}
class MyService3 {
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
public void Aawait() {
try {
lock.lock();
System.out.println("C...等待");
conditionA.await();
System.out.println("C...被唤醒");

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void Bawait() {
try {
lock.lock();
System.out.println("D...等待");
conditionA.await();
System.out.println("D...被唤醒");

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("锁被释放了");
}
}
public void Asignal(){
try {
lock.lock();
conditionA.signal();

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void Bsignal(){
try {
lock.lock();
conditionB.signal();

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
     运行结果:  线程C(基于conditionA)和线程D(基于conditionB)都存于等待状态,主线程在3s后,利用conditionA唤醒了线程C,而线程D依旧处于等待状态,这也就达到了我们利用多个condition去部分通知等待线程。

  JAVA多线程-Lock的使用(一)-ReentrantLock与Condition