我有一个处理某事的类。我正试图并行运行这个类的一些实例。
但是,我不确定在TaskManager.startAll()
中,当我调用r.go()
时,是否会导致r开始在自己的线程中运行,或者在主线程内运行?
我获得的总执行时间似乎非常高,尽管我尝试优化,但似乎没有任何效果。此外,如果我在Netbeans中的项目上运行一个分析器,它会显示所有线程都处于休眠状态。所以我想知道我做错了什么?
这是班级的结构:
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<TaskRunner> 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();
}
}
}
答案 0 :(得分:4)
的确,你并非“做得对”。如果要创建多线程Java应用程序,那么首先要使用java.util.concurrent
包。
从您的代码中可以看出,您希望并行运行十个任务。我假设在“数字运算和处理”之后,你需要聚合结果并在主线程中对它们做一些事情。为此,invokeAll()
的{{1}}方法效果很好。
首先,实施ExecutorService
来完成您在Callable
方法中展示的工作。
process()
然后创建您的任务并运行它们。这将取代您的final class YourTask implements Callable<YourResults> {
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()
答案 1 :(得分:3)
但是,我不确定在调用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();
}
}
请注意,您应该仔细处理线程中断。在运行循环时测试isInterrupted()
并在抛出InterruptedException
时重新中断线程总是一个很好的模式。
我获得的总执行时间似乎非常高,尽管我尝试优化,但似乎没有任何效果。此外,如果我在Netbeans中的项目上运行一个分析器,它会将所有线程显示为休眠状态。
因此虽然线程大多是休眠状态,但由于你的Thread.sleep(1)
,它们仍然每秒循环1000次。如果你增加了休眠时间(使isRunning
成为volatile
之后),它们会循环较少,但正确的机制是使用wait / notify来通知线程。
答案 2 :(得分:2)
糟糕的解决方案,可怕。首先,我强烈建议您开始阅读一些教程,如[this] 其次,如果线程应该等待某个工作的信号,那么为什么不等你呢!!!!!,这样的事情
import java.util.ArrayList;
public class TaskManager
{
//////////////////////
public volatile static Signal wait=new Signal();
//////////////////////
private ArrayList<TaskRunner> 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,并且因为if线程处于等待状态而中断线程。
我希望我可以证明你的解决方案就像梦想故事一样,也可以解释我的解决方案。 有一个很好的并行应用程序:)