java - Java SynchronizedCounter 无法按预期工作
问题描述
我有一堂课
class SynchronizedCounter {
private int i = 0;
public synchronized void increment() {
i++;
}
public synchronized void decrement() {
i--;
}
public synchronized int getValue() {
return i;
}
}
像这样使用:
public class CounterTest {
public static void main(String[] args) throws InterruptedException {
SynchronizedCounter c = new SynchronizedCounter();
Thread d = new Thread(new D(c));
Thread e = new Thread(new E(c));
d.start();
e.start();
System.out.println(c.getValue());
}
}
其中 D 类实现如下:
class D implements Runnable {
private SynchronizedCounter counter;
D(SynchronizedCounter counter) {
this.counter = counter;
}
@Override
public void run() {
counter.increment();
}
}
E类与D类相比只有一条不同的线路
counter.decrement();
在它的运行方法中。
我希望总是打印 0,因为 SynchronisedCounter 类的方法都是同步的,但是有时我会得到 1。你能解释一下这段代码有什么问题吗?当我在 synchronized(c) 块中运行 d.start() 和 e.start() 时,它按预期工作,当我在 d.start() 和 e.join() 之后添加 d.join() 时也会发生同样的情况e.start()。
解决方案
您对不正确的线程做出了很多假设。您的两个不成立的主要假设是:
- 所有线程都以相同的速度运行。
- 所有线程都立即启动。
执行顺序是随机的。线程同时运行。在下文中,sequence 表示线程SynchronizedCounter
通过方法调用命中的顺序。因为这就是这样synchronized
做的,它通过用监视器保护并发线程来强制进行顺序访问(如果您不知道监视器是什么,请改为读取互斥信号量,它是不同的,但对于这个解释来说,差异并不重要)。您可以期待以下三个输出中的任何一个:
0
如果顺序是 D、E、main;或 E、D、主要;或主要、D、E;或主要,E,D。1
如果序列是 D、main、E-1
如果顺序是 E、main、D。
线程不会立即启动
当您调用new Thread().start()
时,将Thread
变为可运行。但由调度程序决定线程何时真正获得 CPU 时间。这取决于程序影响范围之外的因素,有时甚至是 VM 影响范围之外的因素。例如,任何现有线程由于时间片耗尽而被抢占的可能性有多大,或者空闲 CPU 内核现在是否可用。
线程以不同的速度运行
线程的速度由程序影响范围之外的各种因素决定。例如,如果线程要访问数据,该数据是否被缓存,在哪个缓存中,仅举一个例子。
输出-1
是最不可能的输出,但即使是那个输出也不能完全排除。而且“不太可能”也纯粹基于对虚拟机通常行为方式的观察所做出的假设,它不是任何可以依赖的东西。
推荐阅读
- reactjs - 为什么 ReactJS 组件的 handleChange 方法出现 setState undefined 错误?
- javascript - SyntaxError:提取 API 中的输入意外结束
- python-3.x - 为什么使用 python3 google analytics v4 时 ga:clientId 维度请求返回空数组?
- security - 微前端如何使用 Apache Wicket 工作?
- php - 我无法让我的搜索查询正确执行,它不断拉起重复的行
- r - 如何从R中列表内的数据框中提取和组合行
- git - git:总是强制 repo 的 windows 行结尾
- reactjs - React color ChromePicker alpha 滑块不起作用。是否需要使用 Alpha 个人 API?
- r - 如何从 str_extract 中提取确切的字符串?
- typescript - Vue 无法解析父文件夹中的 index.vue