我正在尝试对具有多个线程的相同字符串执行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();
但是,第二个线程仅在第一个线程完成后执行,从而无法拥有多个线程。如何让两个线程同时执行,然后在完成后合并结果?
答案 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();
拥抱