下面的内容基本上来自于《Java并发编程实践》, 留个记录~
一, ReentrantLock
ReentrantLock实现了Lock接口,提供了与synchronized 相同的互斥和内存可见性的保证。获得ReentrantLock的锁与进入synchronized 块有着相同的内存语义;释放ReentrantLock锁与退出synchronized块有着相同的内存语义。下面是Lock接口的定义:
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
public interface Lock {
//获得锁对象,如果无法获得锁,就会阻塞,直到可以获取
void lock();
//获得锁对象,能响应中断,如果无法获得锁,并且没有中断事件,线程阻塞
void lockInterruptibly() throws InterruptedException;
//如果能获得锁,则返回true;不能获得锁,返回false,不会阻塞
boolean tryLock();
//同上,只是增加锁获取超时限制
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//释放锁
void unlock();
Condition newCondition();
}
为什么要创建与内部锁如此相似的机制呢?因为内部锁有一些功能上的限制---不能中断那些正在等待获取锁的线程,并且在请求锁失败的情况下,必须无限等待。但是使用ReentrantLock需要注意的是 锁必须在finally中释放。使用如下:
ReentrantLock lock = new ReentrantLock();
...
lock.lock();
try {
//code
} finally {
lock.unlock();
}
具体使用如下:
public class ReentrantLockTest {
private ReentrantLock lock = new ReentrantLock();
private SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
public void printA() {
lock.lock();
System.out.println(format.format(new Date()) + "---printA");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
System.out.println(format.format(new Date()) + "---printB");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static class MyThread extends Thread {
private ReentrantLockTest reentrantLockTest;
private String methodName;
public MyThread(ReentrantLockTest reentrantLockTest, String methodName) {
super();
this.reentrantLockTest = reentrantLockTest;
this.methodName = methodName;
}
@Override
public void run() {
if ("printA".equalsIgnoreCase(methodName))
reentrantLockTest.printA();
else
reentrantLockTest.printB();
}
}
public static void main(String[] args) {
ReentrantLockTest test = new ReentrantLockTest();
MyThread t1 = new MyThread(test, "printA");
MyThread t2 = new MyThread(test, "printB");
t1.start();
t2.start();
}
}
输出的结果如下:
15:34:34---printA
15:34:37---printB
二, ReadWriteLock
ReadWriteLock: 允许读操作并发执行;不允许“读/写”, “写/写”并发执行。当数据结构需要频繁的读时,ReadWriteLock相比ReentrantLock与synchronized的性能更好。
public class ReadWriteLockTest {
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();
public void read() {
readLock.lock();
try {
System.out.println(format.format(new Date()) + "---read---");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
public void write() {
writeLock.lock();
try {
System.out.println(format.format(new Date()) + "---write---");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
public static class MyThread extends Thread {
private ReadWriteLockTest readWriteLockTest;
private String methodName;
public MyThread(ReadWriteLockTest readWriteLockTest, String methodName) {
super();
this.readWriteLockTest = readWriteLockTest;
this.methodName = methodName;
}
@Override
public void run() {
if ("read".equalsIgnoreCase(methodName))
readWriteLockTest.read();
else
readWriteLockTest.write();
}
}
public static void main(String[] args) {
ReadWriteLockTest test = new ReadWriteLockTest();
Thread t1 = new MyThread(test, "read");
Thread t2 = new MyThread(test, "read");
t1.start();
t2.start();
}
}
当methodName都为read时,输出结果如下:
15:56:25---read---
15:56:25---read---读取操作同时执行
当methodName为read/write时,输出结果如下:
15:57:17---write---
15:57:20---read---
读/写同步执行