【问题标题】:is there a way to make a multithread that only calculates on request in java?有没有办法制作一个只在java中请求计算的多线程?
【发布时间】:2020-07-08 16:51:22
【问题描述】:

我为我正在制作的项目尝试了多线程。在项目中,每次调用某个函数时,我都需要多次进行某个计算。我尝试制作一些测试代码来了解如何做,但我无法让它正常工作(当我调试它时,代码似乎工作得很好,但如果我正常运行它,它在第一个周期之后就无法工作)。

在代码中有一个无限循环,它模仿我的项目多次调用函数。我尝试这样做,以便线程在 changeflag 为真时运行,并在每次计算运行后将标志更改为假,这样它就会停止一次又一次地计算它,并且在“调用”函数后我将其更改为真,所以它可以再次计算。

以下是我的代码:

import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Result> queue = new SynchronousQueue<>();
        int loops = 0;
        MyThread[] arr = new MyThread[10];
        ArrayList<Result> ress = new ArrayList<>();

        for (int i = 0; i < arr.length; i++) {
            arr[i] = new MyThread(i, queue);
            arr[i].start();
        }
        while (true) {
            System.out.println(loops++);
            while (ress.size() < arr.length){
                ress.add(queue.take());
            }
            while (!ress.isEmpty()){
                arr[ress.get(0).getSign()].setChangeflag(true);
                ress.remove(0);
            }
        }
    }
}

import java.util.Random;
import java.util.concurrent.BlockingQueue;

public class MyThread extends Thread{
    private boolean changeflag = true;
    private boolean runflag = true;
    private int sign;
    private BlockingQueue<Result> queue;
    Random rnd = new Random();

    public MyThread(int sign, BlockingQueue<Result> queue){
        this.sign = sign;
        this.queue = queue;
    }

    public void run(){
        while (runflag){
            if(changeflag){
                changeflag = false;
                try {
                    queue.put(sense());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public Result sense(){
        return new Result( rnd.nextInt(10), sign);
    }

    public synchronized void setChangeflag(boolean changeflag) {
        this.changeflag = changeflag;
    }
}
public class Result {
    private double res;
    private int sign;

    public Result(double res, int sign) {
        this.res = res;
        this.sign = sign;
    }

    public int getSign() {
        return sign;
    }
}

【问题讨论】:

  • "当我调试它时,代码似乎运行良好,但如果我正常运行它,它在第一个周期之后就无法运行" 欢迎使用并发!我不太明白你想用这段代码实现什么。你能解释一下你的目标是什么吗?为什么不直接运行一个线程来计算结果(或使用线程池)?
  • 我试图做到这一点,所以每次调用某个函数时,我都会得到一组新的结果。在我的实际代码中, sense() 不返回随机数,而是进行一定的计算,除非内容发生变化,否则我不希望它进行该计算。 @m0skit0
  • @m0skit0 我假设您没有收到我的回复通知。所以我正在尝试再次 ping 你。非常感谢您的帮助!
  • 第一次收到但是忘记回复了,不好意思。如果这就是你想要的,那么 run() 方法中的 while 有什么用?为什么要在那里循环?为什么还有阻塞队列?
  • 我的朋友建议这样做。我基本上保持线程运行,但在调用上述函数时更改更改标志,以便它再次运行计算。并且阻塞队列是这样的,主线程将等待所有计算完成,直到它继续。如果您有更好的建议,请全神贯注!就像我说的,我是线程新手,这就是我的朋友建议我这样做的方式。 @m0skit0

标签: java multithreading


【解决方案1】:

我建议使用Executors.newCachedThreadPool()。这将返回一个ExecutorService,您可以使用submit(Callable) 对您的计算进行排队,它返回一个Future,您可以根据需要对其进行阻止。如果您将许多任务排队,您可以根据需要保留Futures 或a list of tasks then submit them to the ExecutorService 的列表。

另请注意it's usually not recommended to extend from Thread

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    我至少可以看出为什么您需要Threads 的唯一原因是在后台等待sense 方法完成时做其他工作。例如渲染一些图形或与用户交互。

    如果您的主要Thread 需要等待每个请求的所有sense 作业完成,那么您不需要Threads。只需在主Thread中直接调用方法sense即可。

    另一方面,如果您需要后台 Thread 执行 sense 工作,而主要 Thread 正在执行其他工作,那么您将需要两个 Threads:一个是主要的,另一个是另一个是后台作业。那么你可能需要一个生产者-消费者模式,其中生产者(主要Thread)创建请求,消费者(后台Thread)执行sense 方法。但是,似乎角色再次转身,就像您想在主要的Thread 中等待所有请求在您提交后完成。如果是这种情况,那么您可以启动所有MyThreads,然后在您准备好等待结果时对它们调用join。例如:

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Objects;
    
    public class Main {
    
        public static class Result {
            private final int index;
            private final Object value;
    
            public Result(final int index,
                          final Object value) {
                this.index = index;
                this.value = value;
            }
    
            public int getIndex() {
                return index;
            }
    
            public Object getValue() {
                return value;
            }
        }
    
        public static class MyRunnable implements Runnable {
            private final int index;
            private final Collection<Result> sharedResults;
    
            public MyRunnable(final int index,
                              final Collection<Result> sharedResults) {
                this.index = index;
                this.sharedResults = Objects.requireNonNull(sharedResults);
            }
    
            @Override
            public void run() {
                final Result res = sense(); //Calculating outside the synchronized block.
                synchronized (sharedResults) { //Synchronizing, because the actual instance of this collection might not be synchronized.
                    sharedResults.add(res);
                }
            }
    
            private Result sense() {
                return new Result(index, "Value" + index);
            }
        }
    
        public static void main(final String[] args) {
            final Thread[] t = new Thread[10];
            final Collection<Result> sharedResults = new ArrayList<>();
    
            for (int i = 0; i < t.length; ++i) {
                t[i] = new Thread(new MyRunnable(i, sharedResults));
                t[i].start();
            }
    
            for (final Thread thread: t)
                try { thread.join(); } catch (final InterruptedException ix) { ix.printStackTrace(); }
    
            sharedResults.forEach(res -> System.out.println("Result " + res.getIndex() + " with value \"" + res.getValue() + "\"."));
        }
    }
    

    另一种方法是使用@m0skit0 建议的ExecutorService,并利用返回的Future 对象等待结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      • 1970-01-01
      • 2019-01-29
      • 2019-11-04
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多