CSDNRGY 2024-06-17 23:55 采纳率: 88.9%
浏览 3
已结题

为什么注释前可以实现 0和1 交替输出,注释后就无法实现0和1交替输出了呢?

原始程序如下:

package demo;

public class AddSubDemo {

    public static void main(String[] args) {
        Resource resource = new Resource();
        new Thread(new AddRunnable(resource)).start();
        new Thread(new AddRunnable(resource)).start();
        new Thread(new SubRunnable(resource)).start();
        new Thread(new SubRunnable(resource)).start();
    }

}

class AddRunnable implements Runnable {

    private Resource resource;

    public AddRunnable(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        while (true) {
            try {
                resource.add();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

}

class SubRunnable implements Runnable {

    private Resource resource;

    public SubRunnable(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        while (true) {
            try {
                resource.sub();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

}

class Resource {
    private int num = 0;
    private boolean flag = true; // true:执行ADD;false:执行SUB

    public synchronized void add() throws InterruptedException {
        if (this.flag == false) {
            super.wait();
        }
        Thread.sleep(1000);
        this.num++;
        flag = false;
        System.out.println(Thread.currentThread().getName() + " " + this.num);
        super.notifyAll();
    }

    public synchronized void sub() throws InterruptedException {
        if (this.flag == true) {
            super.wait();
        }
        Thread.sleep(1000);
        this.num--;
        flag = true;
        System.out.println(Thread.currentThread().getName() + " " + this.num);
        super.notifyAll();
    }
}

日志如下:

Thread-0 1
Thread-3 0
Thread-1 1
Thread-3 0
Thread-1 1
Thread-3 0
Thread-1 1
Thread-3 0
Thread-1 1

将程序中,2个Thread.sleep(1000) 注释掉,日志如下:

Thread-2 3467
Thread-1 3468
Thread-2 3467
Thread-1 3468
Thread-2 3467
Thread-1 3468

为什么注释前可以实现 0和1 交替输出,注释后就无法实现0和1交替输出了呢?

  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-06-17 23:55
    关注

    引自免费微信小程序:皆我百晓生

    这个问题的核心在于线程同步与调度机制的理解。在原始程序中,add()sub() 方法内部使用了 wait()notifyAll() 方法来控制线程的执行顺序,这确保了一个线程(例如执行 add() 的线程)在完成操作并更改 flag 变量后,会唤醒其他等待的线程,从而允许它们继续执行。

    Thread.sleep(1000) 存在时,每次一个线程调用 add()sub() 后,它会暂停1秒,这给另一个线程足够的时间来响应 notifyAll() 调用并获取锁,然后执行其操作。因此,即使多个线程可能同时被唤醒,由于锁的存在和 sleep() 的延迟,线程执行呈现了一种有序的交替模式。

    然而,当 Thread.sleep(1000) 被注释掉后,线程在执行完 add()sub() 方法后立即尝试再次获取锁并执行,而不会给其他线程任何机会。这是因为线程调度器可能会选择同一个线程继续执行,尤其是当系统资源充足且没有其他竞争时。这样,一个线程可能连续多次执行同一方法(add()sub()),导致数字不再交替增加和减少。

    为了解决这个问题并保持交替执行,可以在 add()sub() 方法的末尾添加额外的逻辑来强制线程让出CPU时间片,例如使用 Thread.yield() 方法。但更好的做法是确保在 notifyAll() 调用后线程能够适当释放资源并等待,这可以通过更细致地设计同步机制来实现。

    下面是一个改进后的版本,其中每个线程在执行完操作后都会主动让出锁,确保其他线程有机会执行:

    public class ImprovedResource {
        private int num = 0;
        private boolean flag = true; // true: 执行ADD; false: 执行SUB
    
        public synchronized void add() throws InterruptedException {
            while (this.flag == false) {
                wait();
            }
            this.num++;
            flag = false;
            System.out.println(Thread.currentThread().getName() + " " + this.num);
            notifyAll();
        }
    
        public synchronized void sub() throws InterruptedException {
            while (this.flag == true) {
                wait();
            }
            this.num--;
            flag = true;
            System.out.println(Thread.currentThread().getName() + " " + this.num);
            notifyAll();
        }
    }
    

    在这个版本中,while 循环确保线程在条件不满足时继续等待,直到其他线程改变条件并发出通知。这样,即使没有显式的延时,线程也能正确地交替执行 add()sub() 方法。

    希望这个解释和示例代码能帮助你更好地理解问题的原因,并提供一种解决方案。如果有任何疑问或需要进一步的澄清,请随时提问。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 6月26日
  • 已采纳回答 6月18日
  • 创建了问题 6月17日