如何返回已在4个不同线程中编辑的变量的一个实例?

时间:2013-04-10 14:05:42

标签: java multithreading concurrency

好的,我很抱歉这个头衔。我真的不知道怎么说这个。我会在这里做得更好。

所以,我有2个Java类。我们称之为 FirstClass SecondClass (实现Runnable)。在 FirstClass 中,我正在做一些事情,然后我创建了4个线程。

Thread t1 = new Thread (new SecondClass(s1));
Thread t2 = new Thread (new SecondClass(s2));
Thread t3 = new Thread (new SecondClass(s3));
Thread t4 = new Thread (new SecondClass(s4));

s1 s2 s3 s4 都是 String 类型并持有个人价值观。

然后我马上启动线程。

t1.start();
t2.start();
t3.start();
t4.start();

然后在我的 SecondClass 中,我在默认构造函数中接受这些字符串,如下所示

HashMap<String, Integer> map;

public SearchResults(String s) {
    map.put(s, 0);
}

在run()方法中我正在执行以下操作

public void run() {
    try {   
        System.out.println(map);
    } catch (Exception e) {
        // TODO: handle exception
    }           
}

因此,这个无用程序的结果是 map 打印出4次,有4个不同的值。

我想知道如何返回一个地图的实例,其中包含 t1 的所有值以及 t2 投入等等等。他们都在使用相同的变量 map ,但是每个线程看起来都是自己的事情。

我可以,让线程执行,然后当它们全部完成时,将地图返回到另一个类或其他什么东西?我真的不太了解Threads,所以这让我很困惑。任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:3)

有很多方法可以做到这一点。更好的解决方案是切换并使用ExecutorService而不是自己分叉线程。然后,您可以在Callable<Map>中实施Runnable(而不是SecondClass)并返回每个作业创建的地图。

类似的东西:

// create a thread pool with as many workers as there are jobs
ExecutorService threadPool = Executors.newCachedThreadPool();
List<Future<Map<String, Integer>>> futures =
    new ArrayList<Future<Map<String, Integer>>>();
futures.add(threadPool.submit(new SecondClass(s1)));
futures.add(threadPool.submit(new SecondClass(s2)));
futures.add(threadPool.submit(new SecondClass(s3)));
futures.add(threadPool.submit(new SecondClass(s4)));
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
...
Map<String, Integer> all = new HashMap<String, Integer>();
for (Future<Map<String, Integer>> future : futures) {
    // future.get() throws an exception if your call method throws
    all.putAll(future.get());
}

然后,您的SecondClass实施Callable

public Map<String, Integer> call() {
    ...
    return map;
}

您可以使用的其他一些机制包括:

  • 使用传入(更好)或ConcurrentHashMap(不太好)的共享static
  • 让你的帖子在完成后BlockingQueue上显示结果
  • 加入线程,然后在获取创建的Map的类上调用方法。

答案 1 :(得分:2)

您可以将地图设为 static

private static Map<String, Integer> map = new HashMap<String, Integer>();

这将使您的所有SecondClass实例共享相同的地图。

如果您这样做,请不要忘记正确同步,方法是更改​​为其他Map类型或同步您的写入。您可以阅读该主题here, in the Java Tutorials

答案 2 :(得分:0)

您想要的是使用FutureExecutorService

看看它的javadoc,但是用它可以计算异步并等待Future#get()的结果。最后,您可以将它们一起打印出来。

类似的东西:

public class SearchResults implements Callable {
     // 
}
...
    ExecutorService executor = Executors.newFixedThreadPool(4);
    List<SearchResults> searchResults = new LinkedList<SearchResults>();
    List<Future> results = executor.invokeAll(searchResults);    
    Map<String, Integer> calculatedResults = new HashMap<String, Integer>();

    for (Future result : results) {
        calculatedResults.putAll(result.get());
    }
    // print calculated results

答案 3 :(得分:0)

如果您希望在运行所有线程结束时获得结果,则可能需要查看使用CyclicBarrierCountdownLatch

答案 4 :(得分:0)

正如其他人所说,您可以使用ConcurrentHashMapThreadLocal变量,使用它可以在多个线程中共享变量。
现在进入问题的第二部分,即

  

我可以,让线程执行,然后它们全部执行   完成后,将地图返回到另一个类或什么?

您可以像已经建议的那样使用Future,但在这种情况下,您还必须等待,如果执行尚未完成,您将如何处理不同线程的竞争并通知另一个线程事情。如果您的要求如此,您可以继续这样做。
但我建议你经历一次Observer模式,并检查一下是否可以帮助你满足你的要求。一个类可以观察线程,一旦完成就可以通知。如果有任何问题让我们知道,请尝试实施它。