Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 两个线程引用一个变量_Java_Multithreading_Java Threads - Fatal编程技术网

Java 两个线程引用一个变量

Java 两个线程引用一个变量,java,multithreading,java-threads,Java,Multithreading,Java Threads,我在管理下面的班级 public class RunThreads implements Runnable { static int i; public static void main(String[] args) { RunThreads job = new RunThreads(); Thread alpha = new Thread(job); Thread beta = new Thread(job);

我在管理下面的班级

public class RunThreads implements Runnable {
    static int  i;
    public static void main(String[] args) {
        RunThreads job = new RunThreads();
        Thread alpha = new Thread(job);
        Thread beta = new Thread(job);
        alpha.setName("Alpha");
        beta.setName("beta");
        alpha.start();
        beta.start();
    }
    public void run(){
        for(;i<10;i++){
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}
我知道每次执行时都会得到不同的输出。我的问题是,为什么对于alpha和beta线程,即Alpha0和beta0,输出的i值都是0的两倍

beta线程将i的值增加到1。那么,alpha线程如何输出Alpha0呢


我可能错过了一些很明显的东西。谢谢

当线程A进行更新时,线程B正在读取该值

例如:

A: prints i (current value 0)
B: prints i (current value 0)
A: stores 1 to i
你不能假设这两个动作:

打印循环计数器只需一次。恰恰相反


两个线程并行执行相应的指令;这绝对不能保证结果。

当您访问共享数据时,如果没有同步,事情会很可怕,等等:

不能保证Alpha线程阅读我会看到beta线程的最新更新,反之亦然 两个线程有可能在大致相同的时间启动i++。。。而i++基本上是:

int tmp = i;
tmp++;
i = tmp;
您很容易丢失增量

如果要使此线程安全,应改为使用:


您的输出可能仍然以错误的顺序出现,因为alpha线程可能开始写入Alpha0,而beta线程开始写入beta1,但是beta线程首先获得控制台输出的锁,但是您只能看到每个计数一次。请注意,检查和打印都必须使用getAndIncrement的结果-如果在循环体中调用counter.get,由于操作的交错,仍然可以看到重复的操作。

线程可能在多核体系结构中的单独内核上运行,每个内核都有自己的注册表集或本地缓存,只要不使缓存失效,运行的内核就可能无法访问RAM内存以获取最新值,并将使用缓存的值。要使其按预期工作,必须将变量标记为volatile,这将使每次写入此内存位置时的缓存失效,并直接从RAM获取值

更新:
正如注释中所指出的-volatile不足以使值保持最新,在i++上有一个读写操作。要使其工作,AtomicInteger就足够了,或者在i++周围锁定会稍微贵一些。

这里的简单答案是,无论变量是volatile还是atomic或其他什么,您的两个线程都会在变量值为0时启动,并且只会在打印后更改它

这意味着两个线程都可以在到达i++之前到达打印行


这意味着两者都很可能打印0,除非其中一个延迟足够长的时间,以便另一个更新变量,此时会出现内存模型和数据可见性问题。

您的线程正在加速。他们都在尝试读取和更新同一个变量,并且无法保证操作的顺序。请看@khelwood:Whoops,错过了:@JonSkeet,i变量是静态的,所以线程在这里共享变量,对吗?答案是:使用AtomicInteger,如果你想这样做:是的,我错过了-没有充分阅读问题。抱歉,没错,这是误导;删除该部分。使用volatile变量只能解决一小部分问题。增量是非原子的,增量与获取是分开的,这对这一事实没有帮助。@JonSkeet我同意,你仍然会得到谁先写的竞争条件。根据线程是否在读取i操作和在执行++操作后执行写入内存之间挤压,您将获得10-20范围内的值。如果打印了beta1,则表示i的值已增加到1,因此当alpha中的print语句执行并尝试获取i的值时,它怎么能得到0来打印Alpha0呢?@tarunkt,这就是内存模型的问题所在。在一个线程中更改未同步的变量并不意味着另一个线程看到了新值。它可以看到自己的缓存值。
for(;i<10;i++){ // increasing the loop counter
System.out.println(Thread.currentThread().getName() + i);
int tmp = i;
tmp++;
i = tmp;
import java.util.concurrent.atomic.AtomicInteger;

public class RunThreads implements Runnable {
    static AtomicInteger counter = new AtomicInteger();
    public static void main(String[] args) {
        RunThreads job = new RunThreads();
        Thread alpha = new Thread(job);
        Thread beta = new Thread(job);
        alpha.setName("Alpha");
        beta.setName("beta");
        alpha.start();
        beta.start();
    }
    public void run(){
        int local;
        while ((local = counter.getAndIncrement()) < 10) {
            System.out.println(Thread.currentThread().getName() + local);
        }
    }
}