如何组合多个线程的结果?

时间:2017-06-23 18:28:03

标签: java multithreading

我正在尝试对具有多个线程的相同字符串执行replace操作。鉴于文本和包含目标和替换的字符串数组列表,我已经创建了一个这样做的类:

public class ParallelReplacer implements Runnable {
    private String text = "";
    private List<String[]> targetsAndReplacements = null;

    public ParallelReplacer(String text, List<String[]> targetsAndReplacements) {
        this.text = text;
        this.targetsAndReplacements = targetsAndReplacements;
        run();
    }

    public void run() {
        for(String[] s : this.targetsAndReplacements) {
            this.text = performReplace(text, s);
        }
    }

    private String performReplace(String text, String[] targetAndReplacement) {
        text = text.replace(targetAndReplacement[0], targetAndReplacement[1]);
        return text;
    }
}

我这样执行:

List<String[]> targetsAndReplacements = new ArrayList<String[]>();
targetsAndReplacements.add(new String[] {"a", ""});
targetsAndReplacements.add(new String[] {"e", ""});
targetsAndReplacements.add(new String[] {"i", ""});
targetsAndReplacements.add(new String[] {"o", ""});
targetsAndReplacements.add(new String[] {"u", ""});

String text = "I am trying to perform a replace operation the same string with multiple threads.";
text = new ParallelReplacer(text, targetsAndReplacements.subList(0, targetsAndReplacements.size() / 2)).getResults();
text = new ParallelReplacer(text, targetsAndReplacements.subList(targetsAndReplacements.size() / 2, targetsAndReplacements.size())).getResults();

但是,第二个线程仅在第一个线程完成后执行,从而无法拥有多个线程。如何让两个线程同时执行,然后在完成后合并结果?

3 个答案:

答案 0 :(得分:0)

虽然这可能有助于开始学习多线程,但它对字符串处理没有用。正如评论中所述,它不会有助于以后合并字符串(至少以其当前形式)。

您的问题的答案是 Runnable 提供了在单独的线程中运行功能的方法。但它并没有提供后台线程本身。

为了让它在不同的线程中工作,你需要做这样的事情:

Thread first = new Thread(new ParallelReplacer(text, tars.subList(0, tars.size() / 2)));
Thread second = new Thread(new ParallelReplacer(text, tars.subList(tars.size() / 2, tars.size())));

然后,您需要使用Thread.join API等待后台线程的完成才能获得结果。或者在线程代码中Object.notify,在代码中需要Object.wait

我猜这是一个家庭作业问题,所以我不想再往前走了。但是请注意,编写多线程代码是非常重要的,即使对于经验丰富的开发人员也很难做到。如果这不仅仅是家庭作业,那么使用经过验证的图书馆可以帮助您完成工作。

答案 1 :(得分:0)

您的代码的根本问题在于它从不使用任何线程。

java中的Runnable只是一个有权使用不带参数的void方法run的类,所以你只需像调用任何其他函数一样调用它

启动主题
要使用线程,java拥有它自己的类Thread, 其中thread期望一个实现runnable的类,所以你可以做

ParallelReplacer[] replacers=new ParallelReplacer[{number of threads}];
Thread[] threads=new Thread[{number of threads}];
for(int i=0;i<threads.length;i++){
    replacers[i]=new ParallelReplacer(...);
    threads[i]=new Thread(replacers[i]);
}

这会产生一组Thread个对象,随时可以使用他们应该运行的替换器,但它还没有启动它们。为了产生线程,你在该线程上调用.start(),开始它的执行,与继续运行的主线程分开。

所以你会这样做

for(int i=0;i<threads.length;i++){
    thread[i].start();
}

或者只是在上一个循环中创建它后启动每个

输出
执行的主线程单独运行,并且会在你生成的命令执行完毕之前运行下几个命令(即使下一个命令是返回!),所以你需要在某个时候告诉你的主要等待所有的产生的线程完成

您可以通过在每个衍生线程

上调用join()来完成此操作
for(int i=0;i<threads.length;i++){
    threads[i].join();
}

join的作用是告诉当前正在执行的线程(在这种情况下为main)等待它被调用的线程完成。因此,它必须在一个单独的循环中完成,否则你只需要 启动线程1,
停止线程1
启动线程2
...
并且可能根本不使用线程

在所有线程连接之后,您可以遍历替换器数组,并附加所有结果。

然而
你可以做得更好!所有线程共享同一个堆,这是java分配它的对象的地方。如果你将输入字符串(不可变)更改为StringBuilder(可以在适当位置更改),那么你可以让每个线程更改它的部分,当它们全部加入时,StringBuilder将被取代。

答案 2 :(得分:0)

您的所有程序都在同一个帖子中

一个Runnable它是一个需要作为线程参数传递的接口

您需要在新线程中执行ParallelReplacer的实例

你可能会遇到的问题是如何得到结果,所以,你想要使用回调函数,当线程的执行完成时,调用回调

public interface IMyCallback {
    public void onSucess(String result);
    public void onError();
}

在ParallelReplacer中执行此操作

public class ParallelReplacer implements Runnable {
    //...
    IMyCallback myCallback;

    public ParallelReplacer(String text, List<String[]> targetsAndReplacements, IMyCallback myCallback) 
    {
        this.myCallback = myCallback;
        this.text = text;
        this.targetsAndReplacements = targetsAndReplacements;
        run();
    }


    public void run() {
        for(String[] s : this.targetsAndReplacements) {
            this.text = performReplace(text, s);
        }
        myCallback.sucess(text);

    }

}

从下一个方法中声明:

int finishedThreads = 0;
ArrayList<String> resultsThreads = new ArrayList<String>();

这样做:

public void callMeWhenAThreadFinished(String result){
     finishedThreads++;
     resultsThreads.add(result);         

     if(finishedThreads==2){
           //do what you want to do with the results
     }
}

和此:

//...

Runnable r1 = new ParallelReplacer(someText, targetsAndReplacements.subList(0, targetsAndReplacements.size() / 2),new IMyCallback() {
        @Override
        public void onSucess(String result) {
            callMeWhenAThreadFinished(result);
        }

        @Override
        public void onError() {

        }
    });
new Thread(r1).start(); //You forgot this 

Runnable r2 = new ParallelReplacer(someText, targetsAndReplacements.subList(targetsAndReplacements.size() / 2, targetsAndReplacements.size()),new IMyCallback() {
        @Override
        public void onSucess(String result) {
            callMeWhenAThreadFinished(result);
        }

        @Override
        public void onError() {

        }
    });
new Thread(r2).start();

拥抱