2016-08-29 102 views
1

我是新来的java和尝试与示例程序同步使用multiThreading添加数字到100。以下是我能够提出的代码。当我测试代码时,它有时会给出正确的值4590,但有时不会给出正确的值。任何人都可以指出我在做什么错Java同步问题

class Counter{ 
    Integer counter = 0; 

    public void increment(int i){ 
     synchronized (counter){ 
      counter += i; 
     } 
    } 
} 

class ObjectTest implements Runnable{ 

    int i; 
    Counter blah; 

    public ObjectTest(Counter counter,int i){ 
     blah =counter; 
     this.i = i; 
    } 
    @Override 
    public void run() { 
     blah.increment(i); 
    } 
} 

public class SyncTest { 

    public static void main(String args[]) throws InterruptedException { 
     ThreadPoolExecutor executor = new ThreadPoolExecutor(4,10,60, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy()); 
     Counter counter = new Counter(); 
     for (int index = 0; index < 100; index++) { 
      ObjectTest objectTest = new ObjectTest(counter,index); 
      executor.execute(objectTest); 
     } 
     executor.shutdown(); 
     while (!executor.isTerminated()){ 
      Thread.sleep(1000L); 
     } 

     System.out.println(counter.counter); 
    } 
} 

回答

2

,因为它是一个Integer,这是不可改变的,您不能在counter同步。因此counter += i会创建一个新的Integer对象,该对象与已同步的对象不同。

您可以制作它int counter并有一个单独的Object lock = new Object();,同步lock

+2

您可以在整数(或任何对象)上同步,而不是您正在递增的那个... – RealSkeptic

+0

是的,我的声明适用于此特定代码。你可以在你正在增加的Integer上进行同步,但它不会导致运行良好的代码。 – Kayaman

+0

你显然理解这个问题,但是你的答案与新手想法不太一致。新手不能完全掌握对象,变量和表达式之间的差异。你说“因为Integer是不可变的,但是你真正的意思是”,因为'Integer'对象是不可变的,'counter'变量必须是_mutable_。这是计数器变量的可变性导致的问题,而不是Integer对象的不可变性。 –