Synchronized 内置的Java关键字 Lock是一个Java类
Synchronized 无法判断获取锁的状态 Lock 可以判断是否获取到了锁
Synchronized 会自动释放锁,Lock必须手动释放锁!如果不释放则会导致死锁
Synchronized 线程1(获得锁,阻塞)、线程2(等待...)
Lock锁就不一定会等待下去
Synchronized 默认为可重入锁,不可以中断的,非公平锁;
Lock 可重入锁,可以判断锁 可以手动设置为非公平 / 公平锁
Synchronized 适合锁少量的代码同步问题
Lock 适合锁大量的同步代码
生产者和消费者问题 synchronized 版
面试的笔试题:单例模式 排序算法 生产者-消费者问题
存在问题:
如果存在A B C D 四个线程的话,是否还可以得到正常的结果?
if => 判断一次,会导致虚假唤醒!
虚假唤醒: 在多线程执行过程中,线程间的通信未按照我们设想的顺序唤醒,故而出现数据不一致的问题,得到的结果不符合我们的预期。
注意:同步方法中使用while循环判断可防止虚假唤醒
生产者和消费者问题 JUC 版
Synchronized : wait() notify() => 本地方法 继承Object
Lock: await() signal() => 通过监视器Condition来调用
public class B {
public static void main(String[] args) {
Data02 data = new Data02();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
// 判断等待 业务 通知
// 资源类
class Data02{ // 数字 独立 耦合
private int num = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition(); // 替代同步监控器
// +1
public void increment() throws InterruptedException {
lock.lock();
try {
while( num != 0){ // if 判断会导致虚假唤醒
// 等待
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName() + "=>" + num);
// 通知其他线程 +1完毕
condition.signalAll();
} finally {
lock.unlock();
}
}
// -1
public void decrement() throws InterruptedException {
lock.lock();
try {
while (num == 0) {
//等待
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName() + "=>" + num);
// 通知其他线程-1完毕
condition.signalAll();
} finally {
lock.unlock();
}
}
}
任何一个新的技术,绝对不仅仅是覆盖了原来的技术,有优势和补充!
Condition的优势?=> 实现精准通知唤醒
问题: 现在线程是随机执行的 如何让线程有序执行?
设置一个标志位,每个线程都配置一个同步监视器Condition
/**
* @author liuzhihao 1332673139@qq.com
* A 执行完调用B , B执行完调用C ,C执行完调用A
*/
public class C {
public static void main(String[] args) {
Data03 data03 = new Data03();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data03.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data03.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data03.printC();
}
},"C").start();
}
}
class Data03{ // 资源类 lock
// 私有成员变量
private Lock lock = new ReentrantLock();
private int num = 1; // 1 A 2 B 3 C
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void printA() {
lock.lock();
try {
// 业务代码 ,等待判断 -> 执行 -> 通知
while ( num!= 1) {
// 等待
condition1.await();
}
System.out.println(Thread.currentThread().getName() + "AAAAAAA");
num = 2;
// 唤醒指定的人
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
// 业务代码 ,等待判断 -> 执行 -> 通知
while (num != 2) {
// 等待
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "BBBBBB");
num = 3;
// 唤醒 C
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
// 业务代码 ,等待判断 -> 执行 -> 通知
while (num != 3) {
// 等待
condition3.await();
}
System.out.println(Thread.currentThread().getName() + "CCCCCCC");
num = 1;
// 唤醒A
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Java JUC并发之synchronized与Lock的区别
原文:https://www.cnblogs.com/liuzhhhao/p/15016249.html