打印结果为-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;
}
}
答案 0 :(得分:1)
它在您的示例中有效,因为在t1.join()
和t2.join()
之后,主线程可以看到t1和t2中所做的任何更改。
引用http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.4
线程T1中的最终操作与另一个检测到T1已终止的线程T2中的任何操作同步。
T2可以通过调用T1.isAlive()或T1.join()来完成此操作。
基本上,当线程启动时,应该看到所有先前的更改;线程完成后,其他人可以看到它已经改变的内容。如果线程A启动B,则线程C加入线程B
A B C
|
w1
|
start B --> o
. |
. |
. r1 .
w2 .
| .
| |
o --> join B
|
r2
保证r1看到w1,r2看到w2。
答案 1 :(得分:0)
证明我不需要同步size()方法
实际上,它只能证明您的计数器可以 。 size()
应该是同步的,因为基本上它访问的字段可以同时缓存在多个寄存器中,并且没有任何迹象表明该字段在线程之间共享,几个线程可能正在处理它们的纯本地副本字段没有同步回主存。
当你运行它时没有看到任何问题的事实只是证明以这种方式编写并发代码是个坏主意。
答案 2 :(得分:0)
如果你写
会很好public int synchronized size()