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 - Fatal编程技术网

Java 计数器大小的同步()

Java 计数器大小的同步(),java,multithreading,Java,Multithreading,打印的结果是-20000000,这证明我不需要同步size()方法。但我的理解是我也应该同步size()。这里的真实情况是什么 public class Test { public static void main(String[] args){ Counter c = new Counter(); T1 t1 = new T1(c); T1 t2 = new T1(c); t1.start(); t2.st

打印的结果是
-20000000
,这证明我不需要同步
size()
方法。但我的理解是我也应该同步
size()
。这里的真实情况是什么

public class Test {
    public static void main(String[] args){
        Counter c = new Counter();
        T1 t1 = new T1(c);
        T1 t2 = new T1(c);
        t1.start();
        t2.start();

        try{
            t1.join();
            t2.join();
        } catch (Throwable t) {

        }

        System.out.println("c=" + c.size());
    }   
}

class T1 extends Thread{
    private Counter c;

    public T1(Counter c){
        this.c = c;
    }
    public void run(){
        for(int i=0; i<10000000; i++){
            c.decrement();
        }
    }
}

class Counter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }
    public synchronized void decrement() {
        c--;
    }
    public int size() {
        return c;
    }
}
公共类测试{
公共静态void main(字符串[]args){
计数器c=新计数器();
T1=新的T1(c);
T1 t2=新的T1(c);
t1.start();
t2.start();
试一试{
t1.join();
t2.连接();
}捕获(可丢弃的t){
}
System.out.println(“c=“+c.size());
}   
}
类T1扩展线程{
私人柜台c;
公共T1(c柜台){
这个.c=c;
}
公开募捐{
对于(int i=0;i
证明我不需要同步size()方法

实际上,这只能证明你的计数器有时可以工作。
size()
应该同步,因为基本上,它访问的字段可以同时缓存在多个寄存器中,并且没有任何类型的指示表明该字段在线程之间共享,多个线程可以在同一字段的纯本地副本上工作,而不会同步回主内存


当您运行它时,您没有看到任何问题,这只是证明以这种风格编写并发代码是个坏主意。

如果您编写

public int  synchronized size()

它在您的示例中确实有效,因为在
t1.join()
t2.join()
之后,在t1和t2中所做的任何更改都对主线程可见

引用

线程T1中的最后一个操作与另一个线程T2中检测到T1已终止的任何操作同步

T2可以通过调用T1.isAlive()或T1.join()来实现这一点

基本上,当一个线程启动时,它应该看到所有先前的更改;当一个线程完成后,它所做的更改应该对其他线程可见

    A         B        C
    |
    w1
    |
 start B --> o
    .        |
    .        |
    .        r1       .
             w2       .
             |        .       
             |        |
             o -->  join B
                      |
                      r2
                     

可以保证r1看到w1,r2看到w2。

如果是这种情况,添加“volatile”就足够了,而无需同步?但这是使用多个线程处理共享数据的常见模式(此处为计数器对象)。你为什么说这种风格是个坏主意?@user697911:是的,让字段不稳定也会达到同样的目的。我不会将处理共享可变数据称为“公共模式”,而更不会将其称为“公共反模式”。许多在该领域有丰富经验的非常聪明的人强烈反对这种做法。然而,计数器类本身是不安全的。在Java中,并发性很难做到正确,而不会将糟糕的封装混为一谈。