Java Lock
java.util.concurrent.locks包常用类及接口
Lock
与ReadWriteLock
是锁的根接口- Lock 接口的主要实现类是 ReentrantLock,ReadWriteLock的主要实现类是 ReentrantReadWriteLock
- ReentrantReadWriteLock 包括两个成员内部类,ReadLock 和 WriteLock
Lock 接口
public interface lock {
/**
* 获取锁,如果锁已被其它线程获取则等待。
*/
void lock();
/**
* 获取锁,如果锁已被其它线程获取则等待。
* 以下两种情况线程会停止等待:
* 1. 线程成功获取锁
* 2. 响应中断,其它线程可以中断当前线程的等待状态
*/
void lockInterruptibly() throws InterruptedException;
/**
* 获取锁,立即返回,不等待
* @return true: 成功获取锁
* @return false: 获取锁失败,锁已被其它线程占用
*/
boolean tryLock();
/**
* 获取锁,在没有获取锁时会等待 time 时间
* @return true: 一开始就成功获取锁 或 在等待期间内成功获取锁
* @return false: 获取锁失败
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**
* 释放锁, 使用 Lock 必须手动释放锁
*/
void unlock();
/**
* 返回一个绑定到Lock对象上的 Condition 实例
* 在等待条件之前,当前线程必须持有锁
* 调用 Condition.await() 方法会自动释放锁, 并在等待返回之前获取锁
*/
Condition newCondition();
}
ReadWriteLock 接口
public interface ReadWriteLock {
/**
* 读锁共享
* Returns the lock used for reading.
* @return the lock used for reading
*/
Lock readLock();
/**
* 写锁独占
* Returns the lock used for writing.
* @return the lock used for writing
*/
Lock writeLock();
}
ReentrantLock 示例
Resource 资源类
public class Resource {
private int num;
public Resource() {}
public Resource(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public void doSomething() {
System.out.println("Do some operation.");
}
public void doLogging() {
System.out.println("Do logging.");
}
}
ReentrantLockExample 类
public class ReentrantLockExample implements Runnable{
private Resource resource;
private Lock lock;
public ReentrantLockExample(Resource resource) {
this.resource = resource;
this.lock = new ReentrantLock();
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
// 尝试获取锁
if (lock.tryLock(10, TimeUnit.SECONDS)) {
resource.doSomething();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
resource.doLogging();
}
public static void main(String[] args) {
Runnable worker = new ReentrantLockExample(new Resource());
new Thread(worker).start();
}
}
ReentrantReadWriteLock 示例
ReadWriteLockExample 类
public class ReadWriteLockExample {
private Resource resource;
private ReadWriteLock readWriteLock;
public ReadWriteLockExample(Resource resource) {
this.resource = resource;
this.readWriteLock = new ReentrantReadWriteLock();
}
public void read() {
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " start to read data.");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " end to read data: " + resource.getNum());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
public void write(Resource resource) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " start to write data.");
Thread.sleep((long) (Math.random() * 1000));
this.resource = resource;
System.out.println(Thread.currentThread().getName() + " end to write data: " + this.resource.getNum());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
public static void main(String[] args) {
ReadWriteLockExample example = new ReadWriteLockExample(new Resource(0));
// 分别启动5个读写数据线程
for (int i = 0; i < 5; i++) {
new Thread() {
@Override
public void run() {
while (true) {
example.read();
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
Resource resource = new Resource((int) (Math.random() * 1000));
example.write(resource);
}
}
}.start();
}
}
}
Synchronized
Synchronized 关键字获取锁
public class SynchronizedExample implements Runnable{
private Resource resource;
public SynchronizedExample(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
synchronized(resource) {
resource.doSomething();
}
resource.doLogging();
}
}
Synchronized 锁的是什么
class T {
private Resource resource;
public synchronized void methodA(){}
public synchronized static void methodB(){}
public void methodC() {
synchronized(resource) {
// Do something
}
}
}
// 上面的代码相当于
class T {
public synchronized(this) void methodA(){}
public synchronized(T.class) static void methodB(){}
public void methodC() {
synchronized(resource) {
// Do something
}
}
}
- 对于非静态方法,synchronized 锁的是this即实例对象
- 对于静态方法,synchronized 锁的是T.class即类对象(每个类都有一个类对象)
- 对于同步代码块,则锁的括号里的对象
Synchronized 与 Lock 的区别
- Java Lock API 为锁提供了更多的可见性和选项,可以使用 tryLock() 方法保证线程只会等待等定的时间,而 synchronized 可能使线程无限制等待,产生死锁。
- synchronized 代码块更加简洁,不需要手动释放锁;Lock则必须使用 try-finally 代码块来保证在发生异常情况下也能释放锁。
- synchronized 方法或代码块只能覆盖一个方法;Lock则可以跨越多个方法。
- synchronized 不支持公平锁;Lock则可以通过设置参数创建一个公平锁。
- Lock可以创建不同的 Condition,不同的线程可以为不同的条件创建 await()。
参考文章:
[1] Java Lock
[2] Java锁Lock接口详解