首页 > 解决方案 > 没有为 Runnable 类型的类 Task 执行 Run 方法

问题描述

我是多线程的新手,在下面给出的情况下,我试图将所有任务中的 a 和 b 的值相加并将其保存在finalAnswer变量中。但不知何故,我的运行方法没有被触发。请让我知道缺少什么。可能有很多愚蠢的错误为同样的道歉。

package MultiThreading;

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

public class Executor {

static List<Task> list = new LinkedList<Task>();

public static void main(String[] args) {
    Task t1 = new Task(1, 2, "u1");
    Task t2 = new Task(3, 4, "u2");
    Task t3 = new Task(5, 6, "u3");
    Task t4 = new Task(7, 8, "u1");
    Task t5 = new Task(9, 10, "u2");
    Task t6 = new Task(11, 12, "u3");
    Task t7 = new Task(13, 14, "u1");
    Task t8 = new Task(15, 16, "u2");
    Task t9 = new Task(17, 18, "u3");

    list.add(t1);
    list.add(t2);
    list.add(t3);
    list.add(t4);
    list.add(t5);
    list.add(t6);
    list.add(t7);
    list.add(t8);
    list.add(t8);

    ExecutorService executor = Executors.newFixedThreadPool(5);
    list.stream().forEach(x -> executor.submit(() -> new Task(x.a, x.b, x.userName)));

    System.out.println(" finalAnswer " + Task.finalAnswer);

}

static class Task implements Runnable {

    int a;
    int b;
    String userName;

    public Task(int a, int b, String userName) {
        this.a = a;
        this.b = b;
        this.userName = userName;
        System.out.println(" a " + a + " b " + b + " userName " + userName);
    }

    static Integer finalAnswer = 0;

    @Override
    public void run() {
        finalAnswer += (a + b);
        System.out.println(" Thread info " + Thread.currentThread().getName());
    }

}

}

请,建议。

标签: javamultithreading

解决方案


这一行:

list.stream().forEach(x -> executor.submit(() -> new Task(x.a, x.b, x.userName)));

没有做我认为你认为的事情。

这是提交一个可运行的,它只是创建一个新任务。有效:

list.stream().forEach(x -> executor.submit(new Runnable() {
  @Override public void run() {
    new Task(x.a, x.b, x.userName);
  }
});

它实际上并没有运行该Task.run()方法。

所以,你可以:

  • 直接调用run()() -> new Task(x.a, x.b, x.userName).run()
  • 提交new Taskexecutor.submit(new Task(x.a, x.b, x.userName))
  • 但是,为什么要TaskTask实现时创建 new Runnable:(executor.submit(x)或者更简单,使用list.forEach(executor::submit))。

但是,您会遇到finalAnswer变量更新的原子性和可见性问题。

  • finalAnswer += (a + b);不是原子的:它是finalAnswer = finalAnswer + (a + b). 没有什么能阻止另一个线程finalAnswer在读取和写入之间写入。
  • System.out.println(" finalAnswer " + Task.finalAnswer);不保证看到 的更新值finalAnswer

最简单的解决方案是相互同步对finalAnswer变量的访问:

synchronized (Task.class) {
  System.out.println(" finalAnswer " + Task.finalAnswer);
}

//

synchronized (Task.class) {
  finalAnswer += (a * b);
}

AtomicInteger也存在其他解决方案,例如使用。

但总的来说,这是对执行器框架的一个非常糟糕的使用:最好是提交Callable<Integer>给执行器,然后在主线程中将所有结果相加。


推荐阅读