ReentrantLock
优点
- 可重入
- 可中断
- 可限时
- 公平锁
一般用法
public class Starter extends Thread {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
public Starter(String name) {
super.setName(name);
}
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
lock.lock();
try {
System.out.println(this.getName() + " " + i);
i++;
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Starter test1 = new Starter("Thread1");
Starter test2 = new Starter("Thread2");
test1.start();
test2.start();
test1.join();
test2.join();
System.out.println(i);
}
}
// 使用 ReentrantLock,输出结果:
….
Thread2 199959
Thread2 199960
Thread2 199961
199962// 不使用 ReentrantLock,输出结果:
….
Thread2 199997
Thread2 199998
Thread2 199999
200000
可重入
lock.lock();
lock.lock();
try {
i++;
}
finally {
lock.unlock();
lock.unlock();
}
可中断
public class Starter extends Thread {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public Starter(int lock, String name) {
super(name);
this.lock = lock;
}
@Override
public void run() {
try {
if (lock == 1) {
lock1.lockInterruptibly();
try {
Thread.sleep(500);
} catch (Exception e) {
}
lock2.lockInterruptibly();
} else {
lock2.lockInterruptibly();
try {
Thread.sleep(500);
} catch (Exception e) {
}
lock1.lockInterruptibly();
}
} catch (Exception e) {
} finally {
if (lock1.isHeldByCurrentThread()) {
lock1.unlock();
}
if (lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
System.out.println(Thread.currentThread().getId() + " : 线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
Starter s1 = new Starter(1, "LockInterrupt1");
Starter s2 = new Starter(2, "LockInterrupt2");
s1.start();
s2.start();
Thread.sleep(1000);
DeadLockChecker.check();
}
static class DeadLockChecker {
private final static ThreadMXBean mBean = ManagementFactory.getThreadMXBean();
public static void check() {
Thread tt = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
long[] deadLockedThreadIds = mBean.findDeadlockedThreads();
if (deadLockedThreadIds != null) {
ThreadInfo[] threadInfos = mBean.getThreadInfo(deadLockedThreadIds);
for (Thread thread : Thread.getAllStackTraces().keySet()) {
for (int i = 0; i < threadInfos.length; i++) {
if (thread.getId() == threadInfos[i].getThreadId()) {
System.out.println(thread.getName());
thread.interrupt();
}
}
}
}
try {
Thread.sleep(5000);
} catch (Exception e) {
}
}
}
});
tt.setDaemon(true);
tt.start();
}
}
}
输出结果:
LockInterrupt2
LockInterrupt1
11 : 线程退出
10 : 线程退出
可限时
public class Starter extends Thread {
public static ReentrantLock lock = new ReentrantLock();
public Starter(String name) {
super(name);
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
if (lock.tryLock(3, TimeUnit.SECONDS)) {
Thread.sleep(5000);
} else {
System.out.println(this.getName() + " get lock failed");
}
} catch (Exception e) {
} finally {
if (lock.isHeldByCurrentThread()) {
System.out.println("lock.isHeldByCurrentThread : " + this.getName());
lock.unlock();
}
}
}
public static void main(String[] args) {
Starter s1 = new Starter("TryLockTest1");
Starter s2 = new Starter("TryLockTest2");
s1.start();
s2.start();
}
}
输出结果:
TryLockTest1 get lock failed
lock.isHeldByCurrentThread : TryLockTest2
公平锁
public static ReentrantLock fairLock = new ReentrantLock(true);
注意事项
为了保证锁最终被释放,要把互斥区放在 try 里面,释放锁放在 finally 里面。
ReadWriteLock
优点
写线程需要互斥,读线程不需要互斥。
例子
public class Starter {
private int data;
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void set(int data) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " : 准备写入数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data;
System.out.println(Thread.currentThread().getName() + " : 写入" + this.data);
} finally {
readWriteLock.writeLock().unlock();
}
}
public void get() {
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " : 准备读取数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " : 读取" + this.data);
} finally {
readWriteLock.readLock().unlock();
}
}
public static void main(String[] args) {
final Starter data = new Starter();
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int j = 0; j < 5; j++) {
data.set(new Random().nextInt(30));
}
}
});
thread.setName("Thread-w " + i);
thread.start();
}
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int j = 0; j < 5; j++) {
data.get();
}
}
});
thread.setName("Thread-r " + i);
thread.start();
}
}
}
Condition
例子
public class Starter {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putPtr;
int takePtr;
int count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await();
}
items[putPtr] = x;
if (++putPtr == items.length) putPtr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await();
}
Object x = items[takePtr];
if (++takePtr == items.length) takePtr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
参考资料