Lock
接口
ReentrantLock
是
Lock
的具体类,
Lock
提供了以下一些方法:
-
lock():
请求锁定,如果锁已被别的线程锁定,调用此方法的线程被阻断进入等待状态。
-
tryLock()
:如果锁没被别的线程锁定,进入锁定状态,并返回
true
。若锁已被锁定,返回
false
,不进入等待状态。此方法还可带时间参数,如果锁在方法执行时已被锁定,线程将继续等待规定的时间,若还不行才返回
false
。
-
unlock()
:取消锁定,需要注意的是
Lock
不会自动取消,编程时必须手动解锁。
代码:
//
生成一个锁
Lock lock = new ReentrantLock();
public void accessProtectedResource() {
lock.lock(); //
取得锁定
try {
//
对共享资源进行操作
} finally {
//
一定记着把锁取消掉,锁本身是不会自动解锁的
lock.unlock();
}
}
|
ReadWriteLock
接口
为了提高效率有些共享资源允许同时进行多个读的操作,但只允许一个写的操作,比如一个文件,只要其内容不变可以让多个线程同时读,不必做排他的锁定,排他的锁定只有在写的时候需要,以保证别的线程不会看到数据不完整的文件。
ReadWriteLock
可满足这种需要。
ReadWriteLock
内置两个
Lock
,一个是读的
Lock
,一个是写的
Lock
。多个线程可同时得到读的
Lock
,但只有一个线程能得到写的
Lock
,而且写的
Lock
被锁定后,任何线程都不能得到
Lock
。
ReadWriteLock
提供的方法有:
-
readLock():
返回一个读的
lock
-
writeLock():
返回一个写的
lock,
此
lock
是排他的。
ReadWriteLock
的例子:
public class FileOperator{
//
初始化一个
ReadWriteLock
ReadWriteLock lock = new ReentrantReadWriteLock();
public String read() {
//
得到
readLock
并锁定
Lock readLock = lock.readLock();
readLock.lock();
try {
//
做读的工作
return "Read something";
} finally {
readLock.unlock();
}
}
public void write(String content) {
//
得到
writeLock
并锁定
Lock writeLock = lock.writeLock();
writeLock.lock();
try {
//
做读的工作
} finally {
writeLock.unlock();
}
}
}
|
需要注意的是
ReadWriteLock
提供了一个高效的锁定机理,但最终程序的运行效率是和程序的设计息息相关的,比如说如果读的线程和写的线程同时在等待,要考虑是先发放读的
lock
还是先发放写的
lock
。如果写发生的频率不高,而且快,可以考虑先给写的
lock
。还要考虑的问题是如果一个写正在等待读完成,此时一个新的读进来,是否要给这个新的读发锁,如果发了,可能导致写的线程等很久。等等此类问题在编程时都要给予充分的考虑。
Condition
接口:
有时候线程取得
lock
后需要在一定条件下才能做某些工作,比如说经典的
Producer
和
Consumer
问题,
Consumer
必须在篮子里有苹果的时候才能吃苹果,否则它必须暂时放弃对篮子的锁定,等到
Producer
往篮子里放了苹果后再去拿来吃。而
Producer
必须等到篮子空了才能往里放苹果,否则它也需要暂时解锁等
Consumer
把苹果吃了才能往篮子里放苹果。在
Java 5.0
以前,这种功能是由
Object
类的
wait(), notify()
和
notifyAll()
等方法实现的,在
5.0
里面,这些功能集中到了
Condition
这个接口来实现,
Condition
提供以下方法:
-
await()
:使调用此方法的线程放弃锁定,进入睡眠直到被打断或被唤醒。
-
signal():
唤醒一个等待的线程
-
signalAll()
:唤醒所有等待的线程
Condition
的例子:
public class Basket {
Lock lock = new ReentrantLock();
//
产生
Condition
对象
Condition produced = lock.newCondition();
Condition consumed = lock.newCondition();
boolean available = false;
public void produce() throws InterruptedException {
lock.lock();
try {
if(available){
consumed.await(); //
放弃
lock
进入睡眠
}
/*
生产苹果
*/
System.out.println("Apple produced.");
available = true;
produced.signal(); //
发信号唤醒等待这个
Condition
的线程
} finally {
lock.unlock();
}
}
public void consume() throws InterruptedException {
lock.lock();
try {
if(!available){
produced.await();//
放弃
lock
进入睡眠
}
/*
吃苹果
*/
System.out.println("Apple consumed.");
available = false;
consumed.signal();//
发信号唤醒等待这个
Condition
的线程
} finally {
lock.unlock();
}
}
}
|
ConditionTester:
public class ConditionTester {
public static void main(String[] args) throws InterruptedException{
final Basket basket = new Basket();
//
定义一个
producer
Runnable producer = new Runnable() {
public void run() {
try {
basket.produce();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
};
//
定义一个
consumer
Runnable consumer = new Runnable() {
public void run() {
try {
basket.consume();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
};
//
各产生
10
个
consumer
和
producer
ExecutorService service = Executors.newCachedThreadPool();
for(int i=0; i < 10; i++)
service.submit(consumer);
Thread.sleep(2000);
for(int i=0; i<10; i++)
service.submit(producer);
service.shutdown();
}
}
|
5: Synchronizer:同步装置
Java 5.0
里新加了
4
个协调线程间进程的同步装置,它们分别是
Semaphore, CountDownLatch, CyclicBarrier
和
Exchanger.
Semaphore:
用来管理一个资源池的工具,
Semaphore
可以看成是个通行证,线程要想从资源池拿到资源必须先拿到通行证,
Semaphore
提供的通行证数量和资源池的大小一致。如果线程暂时拿不到通行证,线程就会被阻断进入等待状态。以下是一个例子:
public class Pool {
ArrayList pool = null;
Semaphore pass = null;
public Pool(int size){
//
初始化资源池
pool = new ArrayList();
for(int i=0; i
pool.add("Resource "+i);
}
//Semaphore
的大小和资源池的大小一致
pass = new Semaphore(size);
}
public String get() throws InterruptedException{
//
获取通行证
,
只有得到通行证后才能得到资源
pass.acquire();
return getResource();
}
public void put(String resource){
//
归还通行证,并归还资源
pass.release();
releaseResource(resource);
}
private synchronized String getResource() {
String result = pool.get(0);
pool.remove(0);
System.out.println("Give out "+result);
return result;
}
private synchronized void releaseResource(String resource) {
System.out.println("return "+resource);
pool.add(resource);
}
}
|
SemaphoreTest:
public class SemaphoreTest {
public static void main(String[] args){
final Pool aPool = new Pool(2);
Runnable worker = new Runnable() {
public void run() {
String resource = null;
try {
//
取得
resource
resource = aPool.get();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
//
用
resource
做工作
System.out.println("I worked on "+resource);
//
归还
resource
aPool.put(resource);
}
};
ExecutorService service = Executors.newCachedThreadPool();
for(int i=0; i<20; i++){
service.submit(worker);
}
service.shutdown();
}
}
|