Javamultithreading似乎没有正确工作

我有一个处理某事的课程。 我试图并行运行这个类的一些实例。

但是,我不确定在调用r.go()时是否在TaskManager.startAll() ,是否会导致r开始在自己的线程中运行,或者在主线程内运行?

我得到的总执行时间似乎非常高,尽管我尝试优化,但似乎没有任何效果。 此外,如果我在Netbeans中的项目上运行一个分析器,它会显示所有线程都处于hibernate状态。 所以我想知道我做错了什么?

这是class级的结构:

 public class TaskRunner implements Runnable { private boolean isRunning = false; public void run() { while(true) { while (! running) { try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } } process(); } } public void go() { isRunning = true; } public void stop() { isRunning = false; } private void process() { //Do some number crunching and processing here } } 

以下是如何运行/管理这些内容:

 public class TaskManager { private ArrayList runners = new ArrayList(); public TaskManager() { for (int i = 0; i < 10; i++) { TaskRunner r = new TaskRunner(); new Thread(r).start(); runners.add(r); } } public void startAll() { for (TaskRunner r : runners) { r.go(); } } } 

实际上,你并没有“做得对”。 如果要创建multithreadingJava应用程序,首先要使用java.util.concurrent包。

从您的代码中可以看出,您希望并行运行十个任务。 我假设在“数字运算和处理”之后,你需要聚合结果并在主线程中对它们做一些事情。 为此, ExecutorServiceinvokeAll()方法运行良好。

首先,实现Callable来完成您在process()方法中显示的工作。

 final class YourTask implements Callable { private final YourInput input; YourTask(YourInput input) { this.input = input; } @Override public YourResults call() throws Exception { /* Do some number crunching and processing here. */ return new YourResults(...); } } 

然后创建您的任务并运行它们。 这将取代你的main()方法:

 Collection> tasks = new List<>(inputs.size()); for (YourInput i : inputs) tasks.add(new YourTask(i)); ExecutorService workers = Executors.newFixedThreadPool(10); /* The next call blocks while the worker threads complete all tasks. */ List> results = workers.invokeAll(tasks); workers.shutdown(); for (Future f : results) { YourResult r = f.get(); /* Do whatever it is you do with the results. */ ... } 

但是,我不确定在调用r.go()时是否在TaskManager.startAll()中,是否会导致r开始在自己的线程中运行,或者在主线程内运行?

所以我的第一个评论是你应该使isRunning变得volatile因为它是在线程之间共享的。 如果线程在启动时没有启动(或者似乎在启动时延迟),那么我怀疑这是你的问题。 volatile提供线程之间的内存同步,因此调用go()并对isRunning进行更改的线程将立即被等待更改的线程看到。

而不是像这样旋转,我会使用wait / notify:

 // this synchronizes on the instance of `TaskRunner` synchronized (this) { // always do your wait in a while loop to protect against spurious wakeups while (!isRunning && !Thread.currentThread().isInterrupted()) { try { // wait until the notify is called on this object this.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } } 

然后在go()方法中,您应该执行以下操作。 stop()会类似。

 public void go() { synchronized (this) { isRunning = true; this.notifyAll(); } } 

请注意,您应该仔细处理线程中断。 在while循环中测试isInterrupted()并在抛出InterruptedException时重新中断线程总是一个好的模式。

我得到的总执行时间似乎非常高,尽管我尝试优化,但似乎没有任何效果。 此外,如果我在Netbeans中的项目上运行一个分析器,它会显示所有线程都处于hibernate状态。

因此,虽然线程大多是hibernate状态,但由于Thread.sleep(1) ,它们仍然每秒循环1000次。 如果你增加了hibernate时间(在使isRunning变为volatile ),它们会循环较少,但正确的机制是使用wait / notify来通知线程。

可怕的解决方案,太糟糕了。 首先我强烈建议你开始阅读一些像[this]这样的教程。其次,如果线程应该等待某个工作的信号,那么为什么你不等他们!!!!!,这样的事情

 import java.util.ArrayList; public class TaskManager { ////////////////////// public volatile static Signal wait=new Signal(); ////////////////////// private ArrayList runners = new ArrayList<>(); public TaskManager() { for (int i = 0; i < 10; i++) { TaskRunner r = new TaskRunner(); new Thread(r).start(); runners.add(r); } try { Thread.sleep(1000); startAll(); Thread.sleep(1000); pauseAll(); Thread.sleep(1000); startAll(); Thread.sleep(1000); haltAll();System.out.println("DONE!"); }catch(Exception ex){} } public void startAll() { synchronized(wait){ wait.setRun(true);; wait.notifyAll(); } } public void pauseAll(){ wait.setRun(false); } public void haltAll(){ for(TaskRunner tx:runners){tx.halt();} } public static void main(String[] args) { new TaskManager(); } } class TaskRunner implements Runnable { private Thread thisThread; private volatile boolean run=true; public void run() { thisThread=Thread.currentThread(); while(run){ if(!TaskManager.wait.isRun()){ synchronized(TaskManager.wait) { if(!TaskManager.wait.isRun()){ System.out.println("Wait!..."); try { TaskManager.wait.wait(); } catch (Exception e) { e.printStackTrace(); break; } } }} process(); } } private double r=Math.random(); private void process(){System.out.println(r);try { Thread.sleep(10); } catch (Exception e) { // TODO: handle exception }} public void halt(){run=false;thisThread.interrupt();} } class Signal{ private boolean run=false; public boolean isRun() { return run; } public void setRun(boolean run) { this.run = run; } } 

在上面的示例中,所有运行程序都工作,直到Signal run boolean为true,并且简单的TaskManager类在每次需要暂停线程时将tit设置为false。 并且关于暂停,它只是将shutdown(run)标志设置为false,并且还因为线程处于等待状态而中断线程。

我希望我可以certificate你的解决方案就像梦想故事一样,也可以解释我的解决方案。 有一个很好的并行应用:)