两种锁synchronize和lock区别?
- 1、synchronize是内置的java关键字,lock是一个java类
- 2、synchronize无法判断获取锁的状态,lock可以判断是否获取到了锁
- 3、synchronize会自动释放锁,lock必须手动释放锁。如果不释放会造成死锁问题
- 4、synchronize线程1(获得锁,阻塞)、线程2(等待,傻傻的等),lock锁就不一定会等待下去
- 5、synchronize可重入锁,不可以中断,非公平。lock,可重入锁,可以判断锁,非公平(可调)
- 6、synchronize适合少量的代码同步问题,lock适合大量的同步代码
以下通过生产者消费者问题举例说明:
synchronize锁解决生产者消费者问题
/**
* Description:synchronize()锁解决生产者消费者问题
* Author:Jizaichun Date:2022/6/14 16:58
*/
/*
线程之间的通信间题:生产者和消费者间题!等待唤醒,通知唤醒
线程交替执行A B操作同一个变量 num =0
A num+1
B num-1
*/
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}, "D").start();
}
}
// 等待,业务,通知
class Data {// 数字 资源类
private int number = 0;
// +1
public synchronized void increment() throws InterruptedException {
while (number != 0) {
// 等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
// 通知其它线程,+1完毕
this.notifyAll();
}
// -1
public synchronized void decrement() throws InterruptedException {
while (number == 0) {
// 等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
// 通知其它线程,-1完毕
this.notifyAll();
}
}
注意 !!!
while (number != 0) {
// 等待
this.wait();
}
// 此处代码块必须用while,如果使用if会造成虚假唤醒问题
/**
* 具体:假设 number此时等于1,即已经被生产了产品如果这里用的是if判断,
* 如果此时A,C两个生产者线程争夺increment()方法执行权假设A拿到执行权,
* 经过判断number!=0成立,则A.wait()开始等待(wait()会释放锁),
* 然后C试图去执行生产方法,但依然判断number!=0成立,则B.wait()开始等待(wait()会释放锁)
* 碰巧这时候消费者线程线程B/D去消费了一个产品,使number=0然后,B/D消费完后调用this.notifyAll();
* 这时候2个等待中的生产者线程继续生产产品,而此时number++ 执行了2次同理,重复上述过程,生产者线程继续wait()等待,
* 消费者调用this.notifyAll();然后生产者继续超前生产,最终导致‘产能过剩’,即number大于1
*
*/
lock锁解决生产者消费者问题
/**
* Description:lock()锁解决生产者消费者问题
* Author:Jizaichun Date:2022/6/14 19:10
*/
public class B {
public static void main(String[] args) {
Data2 data = new Data2();
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 Data2 { // 数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// condition.await(); // 等待
// condition.signalAll(); // 唤醒全部
//+1
public void increment() throws InterruptedException {
lock.lock();
try {
// 业务代码
while (number != 0) {
// 等待
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
// 通知其他线程,我+1完毕了
condition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number == 0) {
// 等待
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
// 通知其他线程,我-1完毕了
condition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
lock锁配合Condition进行细粒度化操作
/**
* Description:通过Condition实现A执行完调用B,B执行完调用C,C执行完再调A,形成一个循环
* Author:Jizaichun Date:2022/6/14 19:23
*/
public class C {
public static void main(String[] args) {
Data3 data = new Data3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printA();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printB();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printC();
}
}, "C").start();
}
}
class Data3 {// 资源类
private int number = 1;// 1A 2B 3C
private final Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public void printA() {
lock.lock();
try {
// 判断、执行、通知
while (number != 1) {
// 等待
condition1.await();
}
System.out.println(Thread.currentThread().getName() + "=>AAAA");
// 唤醒,通知指定的监视器
number = 2;
condition2.signal();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (number != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "=>BBBB");
number = 3;
condition3.signal();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (number != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName() + "=>CCCC");
number = 1;
// 通知condition1监视器
condition1.signal();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}