(上一节的继续)
2.2 使用Lock机制
Java提供了另外一种机制来同步代码块。它是比synchrozied关键字更为强大且弹性的机制。它是基于锁接口和实现了这个接口的类(如ReetrantLock类)。这个机制表现出一些优势,如下所示:
1. 以一种更加弹性的方式允许同步块结构,而使用synchrozied关键字,你必须以一个机构化的方式来获取和释放对于同步块代码的控制。实用Lock接口允许你获取更为复杂的结构去实现你的临界部分。
2. Lock接口提供除synchronized外额外的功能,新功能之一就是它实现了tryLock()方法。这个方法尝试着去获取锁的控制,如果它不能够获取(已经被其它的线程占有),它返回这个锁。Synchronized关键字修饰的方法中,当线程A尝试着去执行synchronized代码块时,而这个synchronized代码块已经被线程B所执行,这时,线程A不得不挂起直到线程B完成它的同步块代码的执行。在Lock实现中,有可以执行tryLock方法,它返回一个布尔值来显示是否那儿有另外的线程运行这个受Lock保护的代码。
3. Lock接口允许读写操作分离,有多个读者和唯一的写者。
4. Lock接口比synchronized关键字提供了更好的性能。
看下面这个例子,比较好阐明这Lock的使用。
定义打印机队列任务,打印服务PrintQueue类。
public class PrintQueue {
/**
* Lock to control the access to the queue.
*/
private finalLock queueLock=new ReentrantLock();
/**
* Method that prints a document
* @param document document to print
*/
public voidprintJob(Object document){
queueLock.lock();
try {
Long duration=(long)(Math.random()*10000);
System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n",Thread.currentThread().getName(),(duration/1000));
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
queueLock.unlock();
}
}
}
定义打印调用类Task,调用对应的打印任务。
public class Task implements Runnable {
/**
* Queue to print the documents
*/
private PrintQueue printQueue;
/**
* Constructor of the class. Initializes thequeue
* @param printQueue
*/
public Task(PrintQueue printQueue){
this.printQueue=printQueue;
}
/**
* Core method of the Job. Sends the documentto the print queue and waits
* forits finalization
*/
@Override
public voidrun() {
System.out.printf("%s: Going to print a document\n",Thread.currentThread().getName());
printQueue.printJob(new Object());
System.out.printf("%s: The document has been printed\n",Thread.currentThread().getName());
}
/**
* @param args
*/
public staticvoidmain(String[] args) {
// Creates the print queue
PrintQueue printQueue=new PrintQueue();
// Creates ten Threads
Thread thread[]=new Thread[10];
for (int i=0; i<10; i++){
thread[i]=new Thread(new Task(printQueue),"Thread "+i);
}
// Starts the Threads
for (int i=0; i<10; i++){
thread[i].start();
}
}
}
运行结构如下:
Thread1: Going to print a document
Thread9: Going to print a document
Thread8: Going to print a document
Thread7: Going to print a document
Thread6: Going to print a document
Thread5: Going to print a document
Thread4: Going to print a document
Thread0: Going to print a document
Thread3: Going to print a document
Thread2: Going to print a document
Thread1: PrintQueue: Printing a Job during 9 seconds
Thread1: The document has been printed
Thread9: PrintQueue: Printing a Job during 8 seconds
Thread9: The document has been printed
Thread8: PrintQueue: Printing a Job during 5 seconds
Thread8: The document has been printed
Thread7: PrintQueue: Printing a Job during 2 seconds
Thread7: The document has been printed
Thread6: PrintQueue: Printing a Job during 0 seconds
Thread6: The document has been printed
Thread5: PrintQueue: Printing a Job during 5 seconds
Thread5: The document has been printed
Thread4: PrintQueue: Printing a Job during 2 seconds
Thread4: The document has been printed
Thread0: PrintQueue: Printing a Job during 7 seconds
Thread0: The document has been printed
Thread3: PrintQueue: Printing a Job during 2 seconds
Thread3: The document has been printed
Thread2: PrintQueue: Printing a Job during 7 seconds
Thread 2: The document has been printed