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();
}
}
分析: 我们可以看到,每个线程都是等待上一个线程打印完毕之后,才继续打印,因为当前线程已经持有锁,但线程之间打印的顺序是随机的。
1.2 使用condition去实现等待/通知
package org.jksoft.thread.reentrantLock;结果: 线程B先执行await()等待通知,主线程睡3s后,调用service的signal()方法,唤醒处于waiting状态的线程B。
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();
}
}
}
1.3 使用多个condition实现通知部分线程:
package org.jksoft.thread.reentrantLock;运行结果: 线程C(基于conditionA)和线程D(基于conditionB)都存于等待状态,主线程在3s后,利用conditionA唤醒了线程C,而线程D依旧处于等待状态,这也就达到了我们利用多个condition去部分通知等待线程。
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();
}
}
}