1 synchronized和lock区别
在笔记本:并发编程中讲过一次,现在再补充些新知识:
1.1
synchronized是Java关键字,属于JVM层面;
Lock是api,属于java.util.concurrent.locks.lock
1.2
synchronized底层使用monitorenter、monitorexit,而wait()、notify()也是基于monitor的,所以wait()、notify()需要在synchronized的同步块中使用。
所以为什么Object类的wait()、notify()可以影响线程同步状态。
而lock(如ReentrantLock)是new出来的。
2
synchronized遇到异常也会强制退出,所以synchronized不会死锁。
而lock需要手动解锁,遇到异样不会自动解锁,所以lock使用不当或遇到异常会死锁。(一般lock()写在try上面,unlock()写在finally里面 )
3
尝试进入synchronized的线程不可被中断,除非异常或正常运行完成
尝试通过lock获得锁的线程可以被中断,只要线程是通过lock.tryLock(long time, TimeUnit unit)方法(因为时间一到就会放弃获取锁,从等待队列中移出到哪呢?????? 压根不是,看正解:
lock()失败会留在同步队列一直尝试
tryLock()失败就失败,不会留在同步队列再次尝试
tryLock(time, timeUnit)失败的话,一段时间后就也不会留在同步队列再次尝试了
lockInterrupibly()失败,留在同步队列一直尝试,但是可以通过在其他线程内调用 阻塞线程.lockInterrupibly(); ,让阻塞线程提前去争抢一次锁,失败继续留在同步队列一直尝试
)
boolean succeed = false;
succeed = lock.tryLock(2, TimeUnit.SECONDS);
if (succeed) {
}
或 lock.lockInterruptibly()方法(当然需要在别的线程中让该等待线程调用interrupt()方法才可让该等待线程被中断)
4
synchronized非公平锁
lock则都可以,通过构造函数的参数来设置,默认非公平锁
5
synchronized不能分组唤醒
ReentrantLock锁可以绑定多个条件condition实现分组唤醒需要唤醒的线程,而不是像synchronized的notify()/notifyAll()那样,要么随机唤醒一个,要么唤醒所有
(Condition condition = new ReentrantLock.newCondition();)
(Condition condition1 = new ReentrantLock.newCondition();)
关于Conditon精确唤醒的例题:
(注意:await()、signal()必须放在lock.lock()、lock.unLock()之间使用!!!!!!!!!否则IllegalMonitorStateException)
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class C20200108 {
private int number =2;
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5() throws InterruptedException {
lock.lock();
while (number!=1){
c1.await();
}
for (int i =0;i<5;i++){
System.out.println(Thread.currentThread().getName() + i);
}
number = 2;
c2.signal();
lock.unlock();
}
public void print10() throws InterruptedException {
lock.lock();
while (number!=2){
c2.await();
}
for (int i =0;i<10;i++){
System.out.println(Thread.currentThread().getName() + i);
}
number = 3;
c3.signal();
lock.unlock();
}
public void print15() throws InterruptedException {
lock.lock();
while (number!=3){
c3.await();
}
for (int i =0;i<15;i++){
System.out.println(Thread.currentThread().getName() + i);
}
number = 1;
c1.signal();
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
C20200108 c20200108 = new C20200108();
new Thread(()->{
for (int i=0;i<10;i++){
try {
c20200108.print5();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"threadA").start();
// TimeUnit.SECONDS.sleep(1);
new Thread(()->{
for (int i=0;i<10;i++){
try {
c20200108.print10();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"threadB").start();
// TimeUnit.SECONDS.sleep(1);
new Thread(()->{
for (int i=0;i<10;i++){
try {
c20200108.print15();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"threadC").start();
}
}