0

好的,我很抱歉标题。我真的不知道如何表达这个。我会在这里更好地尝试。

所以,我有 2 个 Java 类。我们称它们为FirstClassSecondClass(实现 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));

s1s2s3s4都是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 个不同的值。

我想知道如何返回一个map实例,该实例包含t1放入其中的所有值以及t2放入其中的所有值等等。它们都在使用同一个变量map,但每个线程都是自己的事情似乎。

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

4

5 回答 5

3

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

就像是:

// 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创建的类上调用方法。
于 2013-04-10T14:10:48.667 回答
2

您可以将地图设为静态

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

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

但是,如果您这样做,请不要忘记正确同步,方法是更改​​为另一种Map类型或同步您的写入。您可以在 Java 教程中阅读该主题。

于 2013-04-10T14:08:00.707 回答
0

你想要的是使用Futureand ExecutorService

看看它的 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
于 2013-04-10T14:09:54.547 回答
0

如果您想在运行所有线程结束时获得结果,您可能需要查看 usingCyclicBarrier或 a CountdownLatch

于 2013-04-10T14:11:14.317 回答
0

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

我是否可以让线程执行,然后当它们全部完成时,将映射返回到另一个类或其他什么?

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

于 2013-04-10T14:18:48.097 回答