Synchronized
与Lock
的区别
1、原始构成:
synchronized
是关键字,属于JVM层面。
monitorenter
(底层是通过monitor
对象来完成,其实wait/notify
等方法也依赖于monitor
对象,只有在同步块或方法中才能调用wait/notify
等方法)
monitorexit
Lock
是具体的类(java.util.concurrent.locks.Lock
),是API层面的锁。
2、使用方法
synchronized
不需要用户去手动释放锁,当synchronized
代码执行完后系统会自动让线程释放对锁的占用。
ReentrantLock
则需要用户去手动释放锁,若没有主动释放锁,就有可能出现死锁的现象。
需要lock()
和unlock()
方法配合try/finally
语句块来完成。
3、等待是否可中断
synchronized
不可中断,除非抛出异常或者正常运行完成。
ReentrantLock
可中断,
- 设置超时方法
tryLock(long timeout, TimeUnit unit)
。 lockInterruptibly()
方代码块中,调用interrupt()
方法可中断。
4、加锁是否公平
synchronized
非公平锁。
ReentrantLock
两者都可以,默认非公平锁,构造方法可以传boolean
值,true
为公平锁,false
为非公平锁。
5、锁绑定多个条件Condition
synchronized
没有
ReentrantLock
用来实现分组唤醒需要唤醒的线程组,可以精确唤醒,而不是像synchronized
要么随机唤醒一个线程要么唤醒全部线程。
实战Demo
题目:多线程之间按顺序调用,实现A->B->C三个线程启动,要求如下:
A打印5次,B打印10次,C打印15次
紧接着
A打印5次,B打印10次,C打印15次
依次循环10次。
ShareResource
类
public class ShareResource {
private Lock lock;
private String threadName = "A";
public ShareResource(Lock lock) {
this.lock = lock;
}
public void printInfo(int number, String threadName, String nextThreadName, Condition condition, Condition nextCondition) {
lock.lock();
try {
// 判断
while (!threadName.equals(this.threadName)) {
condition.await();
}
// 执行
for (int i = 0; i < number; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
this.threadName = nextThreadName;
// 通知
nextCondition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
SyncAndReentrantLockDemo
类
public class SyncAndReentrantLockDemo {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
ShareResource shareResource = new ShareResource(lock);
Condition a = lock.newCondition();
Condition b = lock.newCondition();
Condition c = lock.newCondition();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.printInfo(5, "A", "B", a, b);
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.printInfo(10, "B", "C", b, c);
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
shareResource.printInfo(15, "C", "A", c, a);
}
}, "C").start();
}
}
运行结果:
A 0
A 1
A 2
A 3
A 4
B 0
B 1
B 2
B 3
B 4
B 5
B 6
B 7
B 8
B 9
C 0
C 1
C 2
C 3
C 4
C 5
C 6
C 7
C 8
C 9
C 10
C 11
C 12
C 13
C 14
...