【问题标题】:Using threads to do multiple things without having a thread for each使用线程做多个事情,而每个事情都没有一个线程
【发布时间】:2013-07-02 05:27:46
【问题描述】:

我有一门课,基本上两次执行相同系列的步骤。听起来像是在哪里多线程你的程序的一个完美的例子。我的问题是,如果我只能用两个线程来做到这一点。这是事情的一般概要

Tester implements Runnable{
    Thread obj1Thread, obj2Thread;
    MyObj obj1, obj2;
    String obj1Results, obj2Results;

    void runTests(){
        obj1Thread = new Thread(this, "ob1 thread");
        obj2Thread = new Thread(this, "ob2 thread");
        obj1.start();//builds up obj1
        obj2.start();//builds up obj2
        if(obj1 and obj2 are finished building){
            System.out.println(obj1);
            System.out.println(obj2);
        }
        obj1Thread.startSecondPhase()//runs a separate function that tests obj1 vs ob2. Essentially test(ob1, ob2)
        obj2Thread.startSecondPhase()//runs a separate function that tests obj2 vs ob1. Essentially test(ob2, ob1)
        if(obj1 and obj2 are finished testing){
            System.out.println(obj1Results);
            System.out.println(obj2Results);
        }     
    }
}

我已经完成了第一部分 - 构建对象 - 工作。我现在的问题是 -

  1. 如何让主线程等待两个线程完成它们的第一部分?也许主线程会在两个对象上执行wait,然后在线程notifyAll 之后他们在主线程上等待?但是线程如何获取主线程呢?也许是this
  2. 如何在不使用新线程和新的特定运行函数创建新类的情况下获得运行函数的“第二阶段”?我不想为每一项小任务都创建一个新课程和所有内容。

为了澄清我特别想要的事件顺序是 -

  1. 主线程初始化并启动两个线程
  2. 两个线程同时构建各自的对象
  3. 当两个线程都完成构建时,它们会暂停。然后主线程将对象按顺序打印出来。
  4. 主线程完成后,两个线程同时将代码继续到测试阶段
  5. 线程完成后,主线程将结果打印出来。可以在这里使用join()

编辑:另外,我如何告诉特定线程我希望它们处理哪些对象?现在我正在以一种 hacky 的方式进行操作(我正在处理线程名称)。

【问题讨论】:

  • 1- CountDownLatch 2- 你可以使用某种标志来告诉 Thread/Runnable 它是哪个运行状态
  • 所以你是说在运行函数中有一个if/elseif(buildComplete) do test?我更喜欢更有说服力的解决方案,但我想如果没有别的办法的话。
  • 然后使用两个Runnables,一个用于构建,一个用于测试——但你说你不想这样做......
  • 是的,但这只是因为我觉得它有点浪费,而且代码很丑。一个特殊的Runnable 类只是为了实现基本上一行代码?也许我太理想化了,但这对我来说是错误的。
  • 你可以在两个线程中使用CountDownLatch(主线程将阻塞它),一旦你添加到计数(在你的线程中)你可以锁定另一个监视器锁主线程然后更新(例如,您可以使用第二个 CountDownLatch 设置为 1)...这意味着您最终会得到 3 个CountDownLatches,构建、等待和测试...

标签: java multithreading synchronization


【解决方案1】:

我会使用更高级别的抽象:使用执行和ExecutorService.invokeAll(Collection<? extends Callable<T>> tasks),它返回Future 的列表。

你的主线程可以

  1. 分派两个任务,
  2. 获得两个期货,
  3. 打印结果,然后
  4. 再分派两个任务

执行器服务和期货将在后台处理所有并发。

编辑

我看到了你的评论:

一个特殊的 Runnable 类只是为了实现基本上一行代码? 也许我太理想化了,但这对我来说是错误的。

在这种情况下,您通常会使用任意内部类:

Future future = executorService.submit(new Runnable() {
    public void run() {
        System.out.println("Asynchronous task");
    }
});

这没有错。当 Java 有 lambda 时,它会变得更短。

  Future future = executorService.submit(() -> {System.out.println("Asynchronous task");});

【讨论】:

  • +1 用于ExecutorService。恕我直言,我没有看到将这两个任务分成不同的类的问题,但这只是我
  • 我对@9​​87654326@ 的东西不是很熟悉,你知道我应该使用哪个实现类吗?我认为threadPool 会很好,但我不能 100% 确定。
  • @Dgrin91 是的。我猜Executors.newFixedThreadPool( 2 ) 应该可以。另外,我会进行基准测试以确保多线程版本实际上更快;)
  • @ewernli 我做到了,而且速度快了约 30%。 newFixThreadPool 是我最终使用的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2011-07-21
  • 1970-01-01
相关资源
最近更新 更多