尝试在runnable中同步方法

我有一个ConcurrentMap,它可以在我的runnables之外实例化,但是在runnables中共享和更新。 我的runnables需要是并发的,但我的concurrentMap更新需要同步以防止替换先前的entrys。 有人能告诉我我做错了什么。

public class ExecutionSubmitExample { public static void main(String[] args) { //Ten concurrent threads ExecutorService es = Executors.newFixedThreadPool(10); List<Future> tasks = new ArrayList(); ConcurrentHashMap concurrentMap = new ConcurrentHashMap(); for (int x = 0; x < 10; x++) { Example example = new Example(concurrentMap, x); Future future = es.submit(example, example); tasks.add(future); } try { for (Future future : tasks) { Example e = future.get(); } for (Entry obj : concurrentMap.entrySet()) { System.out.println("key " + obj.getKey() + " " + obj.getValue()); } es.shutdown(); } catch (ExecutionException e) { throw new RuntimeException(e); } catch (InterruptedException ie) { throw new RuntimeException(ie); } } } 

可运行

 public class Example implements Runnable { ConcurrentHashMap concurrentMap; private int thread; public Example(ConcurrentHashMap concurrentMap, int thread) { this.concurrentMap = concurrentMap; this.thread = thread; } @Override public void run() { for (int i = 0; i < 3; i++) { runAnalysis(i); } } public synchronized void runAnalysis(int index) { if(concurrentMap.containsKey(index)) { System.out.println("contains integer " + index); } else { System.out.println("put " + index + " thread " + thread); concurrentMap.put(index, "thread " + thread); } } } 

结果 – 通知索引0被添加多次而不是一次。 它应该由线程0添加并读取为线程9包含的内容。我不知何故需要从其他线程锁定此方法,直到更新完成。

 put 0 thread 0 put 0 thread 9 put 0 thread 6 put 0 thread 7 put 1 thread 7 put 0 thread 2 put 0 thread 1 put 0 thread 5 put 0 thread 3 put 0 thread 4 contains integer 1 contains integer 1 contains integer 1 contains integer 1 put 2 thread 7 put 1 thread 6 put 1 thread 9 put 1 thread 0 put 0 thread 8 contains integer 2 contains integer 2 contains integer 2 put 2 thread 2 put 2 thread 1 put 2 thread 5 put 2 thread 3 contains integer 1 contains integer 1 contains integer 2 contains integer 2 key 0 thread 8 key 2 thread 3 key 1 thread 0 

在方法上synchronized意味着在this对象上synchronized 。 因为您每次都在创建新对象

 Example example = new Example(concurrentMap, x); 

同步发生在不同的对象上,因此没有任何阻塞。

您需要在共享对象上进行synchronized或使用共享Lock 。 这些可以传递给Example对象,也可以使用Luiggi建议的static字段。 在这种情况下,请注意该字段在其他任何地方都不会同步,否则可能会干扰此执行。

解决方案基于Sotirios Delimanolis,Luiggi Mendoza,Sotirios Delimanolis的回答。

主要

 public class ExecutionSubmitExample { public static void main(String[] args) { ExecutorService es = Executors.newFixedThreadPool(10); List> tasks = new ArrayList<>(); ConcurrentHashMap concurrentMap = new ConcurrentHashMap<>(); for (int x = 0; x < 10; x++) { Example e = new Example(concurrentMap, x); Future future = es.submit(e, e); tasks.add(future); } // -- all threads should be launching, let's get the ExecutionSubmitExample objects try { for (Future future : tasks) { Example e = future.get(); } for (Entry obj : concurrentMap.entrySet()) { System.out.println("key " + obj.getKey() + " " + obj.getValue()); } es.shutdown(); } catch (ExecutionException e) { throw new RuntimeException(e); } catch (InterruptedException ie) { throw new RuntimeException(ie); } } } 

可运行

 public class Example implements Runnable { ConcurrentHashMap concurrentMap; private int thread; private final Object lock = new Object(); public Example(ConcurrentHashMap concurrentMap, int thread) { this.concurrentMap = concurrentMap; this.thread = thread; } @Override public void run() { for (int i = 0; i < 3; i++) { runAnalysis(i); } } public void runAnalysis(int index) { synchronized(lock) { if(concurrentMap.containsKey(index)) { System.out.println("contains integer " + index); } else { System.out.println("put " + index + " thread " + thread); concurrentMap.put(index, "thread " + thread); } } } } 

结果

 put 0 thread 0 contains integer 0 put 1 thread 7 put 2 thread 7 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 key 0 thread 0 key 2 thread 7 key 1 thread 7 

使用ConcurrentMap时应避免同步。 它提供了处理这些类型操作的其他方法。 对于这种情况,putIfAbsent方法应优先于contains,然后是put。

 public void runAnalysis(int index) { if (concurrentMap.putIfAbsent(index, "thread " + thread) == null) { System.out.println("put " + index + " thread " + thread); } else { System.out.println("contains integer " + index); } } 

如果您创建一个新类“RunAnalysis”并在该类中添加方法runAnalysis()的代码,如下所示:

 class RunAnalysis { public synchronized void analyse(ConcurrentHashMap concurrentMap, int thread, int index) { if(concurrentMap.containsKey(index)) { System.out.println("contains integer " + index); } else { System.out.println("put " + index + " thread " + thread); concurrentMap.put(index, "thread " + thread); } } } public class SyncExample implements Runnable { RunAnalysis runAnalysis = new RunAnalysis(); ConcurrentHashMap concurrentMap; private int thread; public SyncExample(ConcurrentHashMap concurrentMap, int thread) { this.concurrentMap = concurrentMap; this.thread = thread; } @Override public void run() { for (int i = 0; i < 3; i++) { runAnalysis.analyse(concurrentMap, thread, i); } } } 

然后输出是:

 put 0 thread 1 put 1 thread 1 put 2 thread 1 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 0 contains integer 1 contains integer 2 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 contains integer 0 contains integer 1 contains integer 2 key 0 thread 1 key 1 thread 1 key 2 thread 1