Java多线程之线程虚假唤醒

本文目录提纲
问题:两个线程对一个初始值为零的变量操作,实现一个线程加一,另一个线程减一,来十次。
问题:四个线程对一个初始值为零的变量操作,实现两个线程加一,另外两个线程减一,来十次。
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();
    }
}


编译结果:

5df809ac772d51a4fd83da001007af6a8bd.jpg
2. 问题:四个线程对一个初始值为零的变量操作,实现两个线程加一,另外两个线程减一,来十次。
于是把上面的代码,线程弄多两个,运行发现出现问题。编译结果如下:

e60a8b7062829696e7d4abe04793a08c793.jpg
通过阅读文档,发现:

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循环中使用
画图:

7dffcd1f4050dccbb85cecd218c5a37a6ad.jpg
将上面代码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();
    }
}


编译结果:

14a8b61726778011b7a5881d6ebf3c55727.jpg
使用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();
    }
}

 

转载于:https://my.oschina.net/architectliuyuanyuan/blog/3083830

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值