shr*_*van 3 java volatile java-threads
无论有没有volatile关键字,我都会得到相同的输出。
我在代码中犯了错误吗?
public class MutliThreadExample extends Thread{
volatile int value;
public static void main(String[] args) throws InterruptedException {
MutliThreadExample thread1 = new MutliThreadExample();
MutliThreadExample thread2 = new MutliThreadExample();
thread1.start();
thread1.join();
thread2.start();
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
value = value + 1;
System.out.println(value + "-" + Thread.currentThread());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我无法volatile在 Java 中正确使用关键字。
我在这方面做错了什么吗?
是的。多件事。
首先,您的应用程序实际上是单线程的(而不是多线程的),因为:
thread1.start();
thread1.join();
thread2.start();
Run Code Online (Sandbox Code Playgroud)
这句话说的是
所以thread1和thread2不会同时运行。
其次,线程执行以下操作:
Thread.sleep(1000);
Run Code Online (Sandbox Code Playgroud)
当您调用 时sleep,缓存在寄存器等中的变量值可能会被写入主内存。这可能会使该代码的行为有所不同,并干扰您尝试进行的任何观察。
第三,他们这样做:
System.out.println(value + "-" + Thread.currentThread());
Run Code Online (Sandbox Code Playgroud)
在println调用中,I/O 堆栈通常会在后台进行一些同步,这也会干扰value. 此外,value自从您增加它以来可能已经发生了变化。
第四,像这样增加变量:
value = value + 1;
Run Code Online (Sandbox Code Playgroud)
value即使声明为,这也不是原子操作volatile。事实上,它是一个读操作,然后是一个加法,然后是一个写操作。如果你写同样的情况
value++; // or ++value;
Run Code Online (Sandbox Code Playgroud)
如果两个线程实际上同时执行这些语句,则由于不同线程对共享变量的读取、添加和写入操作的交错,它们可能偶尔会丢失增量。
(将变量声明为volatile给出了一个线程写入变量与其他线程随后读取同一变量之间的发生之前关系。但这不足以实现可以由两个或多个线程更新的计数器线程安全方式。为此,您需要使用synchronized、 anAtomicInteger或等效项。)
最后,您已将 和 声明value为实例变量MutliThreadExample,并且thread1和thread2是该类的不同实例。这意味着thread1和thread2正在更新不同的 value变量。没有共享变量,因此整个示例毫无意义!
总之,您的代码在两个版本中产生相同的输出,因为它不是多线程的。和sleep调用println也容易干扰“观察”。而且线程无论如何都会更新不同的 value变量。
如果您解决了所有这些问题,那么无论有或没有它,您的代码都不是线程安全的。volatile这两个版本都不能保证产生正确或不正确的答案。他们都会有非确定性行为。
可靠地证明其效果volatile很困难。犯基本的编程错误也无济于事。
| 归档时间: |
|
| 查看次数: |
99 次 |
| 最近记录: |