Java提供另外的机制用来同步代码块。它比synchronized关键字更加强大、灵活。Lockers在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作。它是基于Lock接口和实现它的类(如ReentrantLock)。
参考:http://www.jb51.net/article/45761.htm
Lock的优势:
- 它允许以一种更灵活的方式来构建synchronized块。使用synchronized关键字,你必须以结构化方式得到释放synchronized代码块的控制权。Lock接口允许你获得更复杂的结构来实现你的临界区。
- Lock 接口比synchronized关键字提供更多额外的功能。新功能之一是实现的tryLock()方法。这种方法试图获取锁的控制权并且如果它不能获取该锁,是因为其他线程在使用这个锁,它将返回这个锁。使用synchronized关键字,当线程A试图执行synchronized代码块,如果线程B正在执行它,那么线程A将阻塞直到线程B执行完synchronized代码块。使用锁,你可以执行tryLock()方法,这个方法返回一个 Boolean值表示,是否有其他线程正在运行这个锁所保护的代码。
- 当有多个读者和一个写者时,Lock接口允许读写操作分离。
Lock接口比synchronized关键字提供更好的性能。
看一个示例
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;
/**
* Lockers 在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,
* 在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,
* 从而保证数据的完整性。
*/
public class Lockers {
public static void main(String[] args) throws Exception {
Lockers.testLockTest();
}
public static void testLockTest() throws Exception {
final LockTest lockTest = new LockTest();
// 新建任务1,调用lockTest的addValue方法(计算)
Runnable task1 = new Runnable() {
public void run() {
lockTest.addValue(55.55);
}
};
// 新建任务2,调用lockTest的getValue方法(结果)
Runnable task2 = new Runnable() {
public void run() {
System.out.println("value: " + lockTest.getValue());
}
};
// 新建任务执行服务
ExecutorService cachedService = Executors.newCachedThreadPool();
Future future = null;
// 同时执行任务1三次,由于addValue方法使用了锁机制,所以,实质上会顺序执行
for (int i = 0; i < 3; i++) {
future = cachedService.submit(task1);
}
// 等待最后一个任务1被执行完
future.get();
// 再执行任务2,输出结果
future = cachedService.submit(task2);
// 等待任务2执行完后,关闭任务执行服务
future.get();
cachedService.shutdownNow();
}
/**
* 测试Lock的使用。在方法中使用Lock,可以避免使用Synchronized关键字。
*/
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("开始计算(取得锁),请稍候...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
this.value += v;
this.addtimes++;
System.out.println("计算结束(释放锁)!");
lock.unlock();// 释放锁
}
public double getValue() {
return this.value;
}
}
}
运行结果:
开始计算(取得锁),请稍候...
计算结束(释放锁)!
开始计算(取得锁),请稍候...
计算结束(释放锁)!
开始计算(取得锁),请稍候...
计算结束(释放锁)!
value: 166.64999999999998