参考网上的一个demo,进一步学习了解Java中的Lock使用,demo来自:http://blog.youkuaiyun.com/huang_xw/article/details/7090177
废话不多说,直接上代码,注释写的很详细:
package lock;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Lockers
* 在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,
* 在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,
* 从而保证数据的完整性。在5.0以前,锁定的功能是由Synchronized关键字来实现的。
*/
public class Lockers {
//内部类
public static class LockTest{
Lock lock=new ReentrantLock();
double value=0d;
int addtimes=0;
/**
* 增加value的值,该方法的操作分为2步,而且相互依赖,必须实现在一个事务中
* 所以该方法必须同步,以前的做法是在方法声明中使用Synchronized关键字。
*/
public void addValue(double v){
lock.lock();//取得锁
System.out.println("LockTest addValue: "+v+" "+System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.value+=v;
this.addtimes++;
lock.unlock();//释放锁
}
public double getValue(){
return this.value;
}
}
//相应的测试方法
public static void testLockTest() throws InterruptedException, ExecutionException{
final LockTest lockTest=new LockTest();
//任务1,调用LockTest中的addValue方法
Runnable taskOne=new Runnable() {
@Override
public void run() {
lockTest.addValue(55.55);
}
};
//任务2,调用LockTest中的getValue方法
Runnable taskTwo=new Runnable() {
@Override
public void run() {
System.out.println("LockTest value:"+lockTest.getValue());
}
};
//新建任务执行服务
ExecutorService executorService=Executors.newCachedThreadPool();
Future future=null;
//同时任务1三次,由于addValue方法使用了锁机制,所以,实质上回顺序执行
for(int i=0;i<3;i++){
//submit提交任务并且有返回值
future=executorService.submit(taskOne);
}
//等待最后一个任务1执行完
future.get();
//再执行任务2,输出结果
future=executorService.submit(taskTwo);
//等待任务2的执行结果
future.get();
//关闭服务
executorService.shutdownNow();
}
/**
* ReadWriteLock内置两个Lock,一个是读的Lock,一个是写的Lock。
* 多个线程可同时得到读的Lock,但只有一个线程能得到写的Lock,
* 而且写的Lock被锁定后,任何线程都不能得到Lock。ReadWriteLock提供的方法有:
* readLock(): 返回一个读的lock
* writeLock(): 返回一个写的lock, 此lock是排他的。
* ReadWriteLockTest很适合处理类似文件的读写操作。
* 读的时候可以同时读,但不能写;写的时候既不能同时写也不能读。
*/
public static class ReadWriteLockTest{
//定义读写锁
ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
double value=0d;
int addtimes=0;
/**
* 增加value的值,该方法不允许多个线程同时进入该方法
*/
public void addValue(double v){
//得到writeLock并锁定
Lock writeLock=lock.writeLock();
writeLock.lock();
System.out.println("WriteLock addvalue"+v+" "+System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
try{
//写工作
this.value+=v;
this.addtimes++;
}finally{
//释放writeLock
writeLock.unlock();
}
}
/**
* 获得信息。当有线程在调用addValue方法时,getInfo得到的信息是不正确的。
* 所以也要保证该方法被调用时,没有在调用addValue方法
*/
public String getInfo(){
//得到读锁并锁定
Lock readLock=lock.readLock();
readLock.lock();
System.out.println("ReadLock getInfo"+" "+System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
try{
//读工作
return this.value+" "+this.addtimes;
}finally{
//释放读锁
readLock.unlock();
}
}
}
//相应的测试方法
public static void testReadWriteLockTest() throws InterruptedException, ExecutionException{
final ReadWriteLockTest readWriteLockTest=new ReadWriteLockTest();
//任务1,调用lockTest的addValue方法
Runnable taskOne =new Runnable() {
@Override
public void run() {
readWriteLockTest.addValue(55.55);
}
};
//任务2,调用getInfo方法
Runnable taskTwo=new Runnable() {
@Override
public void run() {
System.out.println("info "+readWriteLockTest.getInfo());
}
};
//新建任务执行服务
ExecutorService executorService=Executors.newCachedThreadPool();
Future future=null;
//新建5个任务,前两个是任务1,后2个事任务2
for(int i=0;i<2;i++){
future=executorService.submit(taskOne);
}
for(int i=0;i<2;i++){
future=executorService.submit(taskTwo);
}
//最后一个任务是任务1
future=executorService.submit(taskOne);
// 这5个任务的执行顺序应该是:
// 第一个任务1先执行,第二个任务1再执行;这是因为不能同时写,所以必须等。
// 然后2个任务2同时执行;这是因为在写的时候,就不能读,所以都等待写结束,
// 又因为可以同时读,所以它们同时执行
// 最后一个任务1再执行。这是因为在读的时候,也不能写,所以必须等待读结束后,才能写。
//等待最一个任务2执行完
future.get();
//关闭服务
executorService.shutdownNow();
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Lockers.testLockTest();
System.out.println("-----------------");
Lockers.testReadWriteLockTest();
}
}