package com.qcby.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author HuangHaiyang
* @date 2020/07/02
* @description: description
* @version: 1.0.0
*/
public class JucTest {
public static void main(String[] args) {
Goods goods=new Goods();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"一號").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"二號").start();
}
static class Goods{
private int number=0;
private Lock lock=new ReentrantLock();
public synchronized void increment() throws InterruptedException {
if (number!=0){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=====>"+number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if(number==0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=====>"+number);
this.notifyAll();
}
}
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
}
一號=====>1
二號=====>0
一號=====>1
四號=====>0
三號=====>1
一號=====>2
二號=====>1
二號=====>0
一號=====>1
三號=====>2
四號=====>1
四號=====>0
三號=====>1
一號=====>2
二號=====>1
二號=====>0
一號=====>1
三號=====>2
四號=====>1
四號=====>0
三號=====>1
一號=====>2
二號=====>1
二號=====>0
一號=====>1
三號=====>2
四號=====>1
四號=====>0
三號=====>1
一號=====>2
二號=====>1
二號=====>0
一號=====>1
三號=====>2
四號=====>1
四號=====>0
三號=====>1
二號=====>0
三號=====>1
四號=====>0
Process finished with exit code 0
上述代碼在只有兩個線程時沒有問題。
但多個線程會出錯。我試了一下,確實會出錯。但是我不能明白爲什麼就會出錯。
不是有synchronized關鍵字加鎖了嗎?其實用if判斷的話,喚醒後線程會從wait之後的代碼開始運行,但是不會重新判斷if條件,直接繼續運行if代碼塊之後的代碼,而如果使用while的話,也會從wait之後的代碼運行,但是喚醒後會重新判斷循環條件,如果不成立再執行while代碼塊之後的代碼塊,成立的話繼續wait。
package com.qcby.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author HuangHaiyang
* @date 2020/07/02
* @description: description
* @version: 1.0.0
*/
public class JucTest {
public static void main(String[] args) {
Goods goods=new Goods();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"一號").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"二號").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"三號").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"四號").start();
}
static class Goods{
private int number=0;
private Lock lock=new ReentrantLock();
public synchronized void increment() throws InterruptedException {
while (number!=0){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=====>"+number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while(number==0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=====>"+number);
this.notifyAll();
}
}
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//一號=====>1
//二號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//三號=====>1
//四號=====>0
//
//Process finished with exit code 0
}
lock鎖實現
package com.qcby.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author HuangHaiyang
* @date 2020/07/02
* @description: description
* @version: 1.0.0
*/
public class JucTest {
public static void main(String[] args) {
Goods goods=new Goods();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"一號").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"二號").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"三號").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
goods.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
} },"四號").start();
}
static class Goods{
private int number=0;
private Lock lock=new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
while (number!=0){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"=====>"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
lock.lock();
try {
while(number==0){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"=====>"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
精確通知
package com.qcby.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author HuangHaiyang
* @date 2020/07/02
* @description: description
* @version: 1.0.0
*/
public class JucTest {
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 { // 資源類 Lock
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1; // 1A 2B 3C
public void printA() {
lock.lock();
try {
// 業務,判斷-> 執行-> 通知
while (number != 1) {
// 等待
condition1.await();
}
System.out.println(Thread.currentThread().getName() + "=>AAAAAAA");
// 喚醒,喚醒指定的人,B
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
// 業務,判斷-> 執行-> 通知
while (number != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "=>BBBBBBBBB");
// 喚醒,喚醒指定的人,c
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
// 業務,判斷-> 執行-> 通知
// 業務,判斷-> 執行-> 通知
while (number != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName() + "=>BBBBBBBBB");
// 喚醒,喚醒指定的人,c
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}