2013-11-27 57 views
3

我在Java 7应用程序上实现Synchronized接口时遇到问题。我认为这个问题可能在于,我正在使用在synchronized方法中写入的静态最终数组实例化多个对象。看起来线程没有确认显示器?我甚至可以做我想做的事情,还是我需要某种具有数组和writeIndex增量器的缓冲区对象? (如果有帮助,代码为https://github.com/dschaper/CS112_Dan_Schaper/tree/master/Week14/Labs这不是功课,这仅仅是一个非分级实验室。)Java 7同步方法似乎允许多线程访问

public class SingleDice extends Dice implements Runnable { 
    String threadName; 
    private static final int[] valuesArray = new int[9]; 
    private static int writeIndex = 0; 

    public SingleDice(String tName) { 
     super(1); 
     threadName = tName; 
    } 

    public synchronized void add(int value) { 
     int pos = writeIndex; 
     System.out.printf("%s starting sync add(%d), writeIndex = %d\n", 
      Thread.currentThread().getName(), value, 
      writeIndex); 
     valuesArray[pos] = value; 
     System.out.printf("%s wrote %d to index %d\n",   
      Thread.currentThread().getName(), value, writeIndex); 
     ++writeIndex; 
     System.out.printf("Next writeIndex %d\n", writeIndex); 
    } 
    @Override 
    public void run() { 
    for (int i = 0; i < 3; i++) { 
     add(super.Throw()); 
     } 
    } 
} 

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class SyncDiceExecutor { 

public static void main(String[] args) { 
    System.out.println("Creating newCachedThreadPool"); 
    SingleDice SD1 = new SingleDice("SD1"); 
    SingleDice SD2 = new SingleDice("SD2"); 
    SingleDice SD3 = new SingleDice("SD3"); 
    ExecutorService executor = Executors.newCachedThreadPool(); 
    executor.execute(SD1); 
    System.out.printf("Starting Thread SD1 %s\n", executor.toString()); 
    executor.execute(SD2); 
    System.out.printf("Starting Thread SD2 %s\n", executor.toString()); 
    executor.execute(SD3); 
    System.out.printf("Starting Thread SD3 %s\n", executor.toString()); 
    executor.shutdown(); 
    System.out.printf("Execeutor shutdown called: %s\n", executor.toString()); 

    } 
} 

输出

Creating newCachedThreadPool 
Starting Thread SD1 [email protected][Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0] 
pool-1-thread-1 starting sync add(4), writeIndex = 0 
pool-1-thread-2 starting sync add(4), writeIndex = 0 
Starting Thread SD2 [email protected][Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0] 
pool-1-thread-2 wrote 4 to index 0 
pool-1-thread-1 wrote 4 to index 0 
pool-1-thread-3 starting sync add(4), writeIndex = 1 
Next writeIndex 1 
pool-1-thread-2 starting sync add(6), writeIndex = 2 
Starting Thread SD3 [email protected][Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0] 
pool-1-thread-2 wrote 6 to index 2 
Next writeIndex 3 
pool-1-thread-3 wrote 4 to index 2 
Next writeIndex 4 
Next writeIndex 2 
pool-1-thread-3 starting sync add(1), writeIndex = 4 
pool-1-thread-2 starting sync add(6), writeIndex = 3 
Execeutor shutdown called: [email protected][Shutting down, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0] 
pool-1-thread-2 wrote 6 to index 4 
Next writeIndex 5 
pool-1-thread-3 wrote 1 to index 4 
Next writeIndex 6 
pool-1-thread-1 starting sync add(3), writeIndex = 4 
pool-1-thread-3 starting sync add(1), writeIndex = 6 
pool-1-thread-1 wrote 3 to index 6 
pool-1-thread-3 wrote 1 to index 6 
Next writeIndex 8 
Next writeIndex 7 
pool-1-thread-1 starting sync add(1), writeIndex = 8 
pool-1-thread-1 wrote 1 to index 8 
Next writeIndex 9 

Process finished with exit code 0 

回答

5

SD1,SD2和SD3是不同对象,即他们不共享相同的显示器。每个对象都有自己的显示器。如果您想在所有实例之间共享显示器,则可以使用synchronized(SingleDice.class){...}。

+0

感谢您的帮助!所以这个方法显式地是'public synchronized void add(int value){synchronized(this)...}',就像我上面编码的那样? (正如@hyde指出的)我只需要明确地将(this)改为(SingleDice.class)。 – SonOfAMotherlessGoat

+0

将方法签名中的'synchronized'与本方法中的'synchronized(this){method body}'做同样的处理。所以你可以从签名中除去'synchronized'并且在方法体上添加'synchronized(SingleDice.class){...}'。 – fpw

+0

'public synchronized void add(int value){ synchronized(SingleDice.class){ int pos = writeIndex; valuesArray [pos] = value; System.out.printf(“%s写入%d到索引%d \ n”,(),value,writeIndex); ++ writeIndex; } }'抱歉,不知道如何在注释中做代码块 – SonOfAMotherlessGoat

1

​​上的非静态方法在this上同步,所以如果你有不同的对象,它们不是相互排斥的。如果你不能使用静态方法(在类上同步),解决方案是添加静态锁定对象并在其上同步以保护静态数据。

static final Object valueArrayLock = new Object(); 

...

// inside a method 
synchronized(valueArrayLock) { 
    // operate on valueArray 
} 

请注意,如果您需要在静态方法来锁定这一点,使用相同的静态锁定的对象,而不是使同步的静态方法(或看到其他答案关于使用类对象进行锁定)。

+0

该对象不是必需的,你可以使用'ClassName.class'。这是每个班级的静态对象。这甚至可以兼容静态方法,因为这正是他们所做的。 – fpw

+1

@fpw我更喜欢显式的,描述性地命名的锁对象的清晰度。如果需要添加另一个锁对象,它也更容易/更清晰。但是,风格问题。 – hyde

+0

当然,我只是想指出,这会破坏与同步静态方法的兼容性 - 如果将两种样式混合,您可以轻松地遇到用餐哲学家问题。 – fpw