本文目录提纲
问题:两个线程对一个初始值为零的变量操作,实现一个线程加一,另一个线程减一,来十次。
问题:四个线程对一个初始值为零的变量操作,实现两个线程加一,另外两个线程减一,来十次。
1. 两个线程对一个初始值为零的变量操作,实现一个线程加一,另一个线程减一,来十次。
代码实现:
class ShareData{
private int number = 0;
public synchronized void increment() throws InterruptedException {
// 判断
if (number!=0){
this.wait();
}
// 干活
++number;
System.out.println(Thread.currentThread().getName()+"\t"+number);
// 通知唤醒
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if (number==0){
this.wait();
}
--number;
System.out.println(Thread.currentThread().getName()+"\t"+number);
this.notifyAll();
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
ShareData sd = new ShareData();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
sd.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 1; i <=10 ; i++) {
try {
sd.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
编译结果:
2. 问题:四个线程对一个初始值为零的变量操作,实现两个线程加一,另外两个线程减一,来十次。
于是把上面的代码,线程弄多两个,运行发现出现问题。编译结果如下:
通过阅读文档,发现:
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
即中断和伪唤醒是可能的,并且这个方法应该在while循环中使用
画图:
将上面代码if换成while再执行,发现没有问题,代码如下:
class ShareData {
private int number = 0;
public synchronized void increment() throws InterruptedException {
// 判断
while (number != 0) {
this.wait();
}
// 干活
++number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
// 通知唤醒
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (number == 0) {
this.wait();
}
--number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
this.notifyAll();
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
ShareData sd = new ShareData();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(200);
sd.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(300); //模拟执行其他代码
sd.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(400);
sd.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(500);
sd.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
编译结果:
使用Lock优化
前置知识:
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use ofsynchronized methods and statements, a Condition replaces the use of the Object monitor methods.
优化代码:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareData {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public synchronized void increment() throws InterruptedException{
lock.lock();
try{
while (number != 0) {
// this.wait();
condition.await();
}
// 干活
++number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
// 通知唤醒
// this.notifyAll();
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public synchronized void decrement() throws InterruptedException{
lock.lock();
try{
while (number == 0) {
// this.wait();
condition.await();
}
// 干活
--number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
// 通知唤醒
// this.notifyAll();
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
ShareData sd = new ShareData();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(200);
sd.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(300);
sd.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(400);
sd.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(500);
sd.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}