java静态字段将在线程之间同步? 公共类ThreadsDemo{ 公共静态int n=0; 专用静态最终整数n读取=300; 公共静态void main(字符串[]argv)引发InterruptedException{ 最终倒计时锁存器cdl=新倒计时锁存器(n次读取); 对于(int i=0;i
为什么输出为“n为:300”?n不是显式同步的。如果我取消注释“Thread.sleep”,则输出为“n为:299或更少” Java静态字段将在线程之间同步 不可以。根据您的使用模式,您应该将其设置为易变的,或者同步对它的所有访问。您最好使用它java静态字段将在线程之间同步? 公共类ThreadsDemo{ 公共静态int n=0; 专用静态最终整数n读取=300; 公共静态void main(字符串[]argv)引发InterruptedException{ 最终倒计时锁存器cdl=新倒计时锁存器(n次读取); 对于(int i=0;i,java,multithreading,synchronization,Java,Multithreading,Synchronization,为什么输出为“n为:300”?n不是显式同步的。如果我取消注释“Thread.sleep”,则输出为“n为:299或更少” Java静态字段将在线程之间同步 不可以。根据您的使用模式,您应该将其设置为易变的,或者同步对它的所有访问。您最好使用它 这个问题将帮助您进行描述和示例:静态上下文需要锁定类而不是对象。如果需要同步静态变量,而不需要将其缓存在本地线程中,则需要将其声明为volatile。我以这种方式更改了代码: public class ThreadsDemo { public s
这个问题将帮助您进行描述和示例:静态上下文需要锁定类而不是对象。如果需要同步静态变量,而不需要将其缓存在本地线程中,则需要将其声明为volatile。我以这种方式更改了代码:
public class ThreadsDemo {
public static int n = 0;
private static final int NTHREADS = 300;
public static void main(String[] argv) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(NTHREADS);
for (int i = 0; i < NTHREADS; i++) {
new Thread(new Runnable() {
public void run() {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
n += 1;
cdl.countDown();
}
}).start();
}
cdl.await();
System.out.println("fxxk, n is: " + n);
}
}
private static final int NTHREADS=300;
私有静态AtomicInteger n=新的AtomicInteger();
公共静态void main(字符串[]argv)引发InterruptedException{
最终倒计时锁存器cdl=新倒计时锁存器(n次读取);
对于(int i=0;i
你必须应付比赛条件。所有300个线程同时修改n
。例如:如果两个线程同时读取并递增n
,则两个线程将n
递增到相同的值
这就是为什么n
并不总是300
,在这种情况下,您会损失一个增量。这种情况可能零次或多次发生
我将n
从int
更改为AtomicInteger
,这是线程安全的。现在一切正常。public-class-ThreadsDemo{
private static final int NTHREADS = 300;
private static AtomicInteger n = new AtomicInteger();
public static void main(String[] argv) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(NTHREADS);
for (int i = 0; i < NTHREADS; i++) {
new Thread(new Runnable() {
public void run() {
n.incrementAndGet();
cdl.countDown();
}
}).start();
}
cdl.await();
System.out.println("fxxk, n is: " + n);
}
公共静态int n=0;
私有静态最终整数n读取=30;
公共静态void main(字符串[]argv)引发InterruptedException{
最终倒计时锁存器cdl=新倒计时锁存器(n次读取);
对于(int i=0;i
输出“n为:29953”
我认为原因是,线程运行的时间很短,jvm不进行上下文切换。一种解释是,您的主线程(即产生其他300个线程的线程)在任何其他线程更改运行并增加
n
计数器之前到达了print语句。顺便说一句,您可能应该使n
线程安全,因为可以有多个线程同时修改它。synchronized(ThreadsDemo.class){n+=1;}
将使它同步我闭着眼睛穿过街道三次,我没有死于事故。这意味着安全吗?不,这只是意味着你很幸运。你使用了Thread.sleep,它让你能够执行同步操作,你得到了300个答案,但正如JB Nizet所建议的,你是幸运的一个,当你注释Thread.sleep时,没有任何停顿的每个线程都会执行,因此你的主线程和所有其他线程都不同步,它会给你299或更少。使其不稳定不会使n+=1原子。没错。Volatile使用lock#指令前缀和内存屏障。但如果旧x在寄存器中。稍后写入内存将隐藏最后一次写入。是的,我知道AtomicInteger,但我的问题是:当n没有显式同步时,为什么输出是300。@RongbinOu你很幸运。多次运行它,将提供不同的结果。@RongbinOu多线程的一个方面是,当您编写非同步代码时,这将以多种方式进行测试,手动测试团队感到沮丧,因为他们无法再现问题的步骤,并且自动测试可能在本地成功运行,但在CI服务器上中断:)我的问题是:当n未显式同步时,为什么输出为300。因为如果幸运的话,不会发生竞速情况。考虑一个单处理器机器,其中线程从不在读取和递增<代码> N< /代码>之间停顿。纯粹是运气。或者将300
减少到2
,您几乎不会观察到与2
不同的值。将300
增加到9999999
,您在多核机器上几乎总能观察到小于9999999
的值:(我使用了3000个线程,但n是正确的。如果我取消注释这些语句,我确实会看到争用条件。在我真正的4核机器上,当使用int
而不是AtomicInteger
时,我观察到的值几乎总是小于300
。您有多少个真正的核?sysctl-n hw.ncpu 8
public class ThreadsDemo {
public static int n = 0;
private static final int NTHREADS = 30;
public static void main(String[] argv) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(NTHREADS);
for (int i = 0; i < NTHREADS; i++) {
new Thread(new Runnable() {
public void run() {
for (int j = 0; j < 1000; j++) // run a long time duration
n += 1;
cdl.countDown();
}
}).start();
}
cdl.await();
System.out.println("fxxk, n is: " + n);
}
}