Java 提供了另一个同步代码块的机制。比 synchronized 更强大、灵活。它是基于 Lock 接口及其实现类(如 ReentrantLock)。 此机制有以下优点:
本节的示例代码在 com.elanzone.books.noteeg.chpt2.sect05 package中
打印队列 (PrintQueue)
private final Lock queueLock = new ReentrantLock();
public void printJob(Object document) { queueLock.lock(); try { Long duration = (long) (Math.random() * 10000); System.out.println(Thread.currentThread().getName() + ": PrintQueue: Printing a Job during " + (duration / 1000) + " seconds"); Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } finally { queueLock.unlock(); } }
线程类 (Job)
private PrintQueue printQueue; public Job(PrintQueue printQueue) { this.printQueue = printQueue; }
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());
控制类 (Main)
PrintQueue printQueue = new PrintQueue();
Thread thread[] = new Thread[10]; for (int i=0; i<10; i++) { thread[i] = new Thread(new Job(printQueue), "Thread" + i); }
for (int i=0; i<10; i++) { thread[i].start(); }
本例的关键在于 PrintQueue 类的 printJob() 方法。 当要用锁实现一个临界区并保证只有一个执行线程运行一个代码块,必须创建一个 ReentrantLock 对象。
在临界区开始,要用 lock() 方法获得对锁的控制。
当线程(A)调用此方法:
在临界区结束,必须使用 unlock() 方法释放对锁的控制并允许其他线程运行此临界区。
Lock 接口(和 ReentrantLock 类)包含其他的方法来获取对锁的控制。那就是 tryLock() 方法。 tryLock 和 lock 的最大的区别在于: * 如果使用 tryLock 的线程不能获得对锁的控制,将立即返回并不会让线程睡眠。
tryLock 方法返回一个 boolean 值: * true : 线程获得对锁的控制 * false : 不能获得
程序员有责任判断 tryLock 方法的返回结果并作出相应处理。如果它返回 false,程序不应执行临界区代码;否则将获得错误的结果。
ReentrantLock 类也允许用于递归调用。当一个线程拥有对锁的控制并递归调用,它继续拥有对锁的控制。这样对 lock() 方法的调用将立即返回,程序也将继续递归执行。 也能调用其他方法。