java-4线程中的多线程自动执行相同操作
我已经写了一个程序来扫描友好的数字(一对两个数字,其中一个的所有除法器之和等于另一个),它工作正常,我将包括下面的整个代码。 我试图让它与几个线程一起运行,因此我将代码移动到一个名为Breaker的类中,我的主要代码如下所示:java-4线程中的多线程自动执行相同操作,java,multithreading,Java,Multithreading,我已经写了一个程序来扫描友好的数字(一对两个数字,其中一个的所有除法器之和等于另一个),它工作正常,我将包括下面的整个代码。 我试图让它与几个线程一起运行,因此我将代码移动到一个名为Breaker的类中,我的主要代码如下所示: Breaker line1 = new Breaker("thread1"); Breaker line2 = new Breaker("thread2"); Breaker line3 = new Breaker("thread3");
Breaker line1 = new Breaker("thread1");
Breaker line2 = new Breaker("thread2");
Breaker line3 = new Breaker("thread3");
Breaker line4 = new Breaker("thread4");
line1.scanRange(1L, 650000L);
line2.scanRange(650001L, 850000L);
line3.scanRange(850001L, 1000000L);
line4.scanRange(1000001L, 1200001L);
现在这确实显著缩短了时间,但这不是一个聪明的解决方案,线程在非常不同的时间结束
我想做的是,使这个过程自动化,这样一个拥有整个范围的主线程将从主线程范围中触发短范围(10000)的部分,当一个线程结束时,在一个新线程中触发下一个部分,直到完成整个主线程范围
我试着理解如何使用synchronized、notify()和wait(),但在几次尝试之后,都以不同的错误和不必要的行为结束
下面是Breaker.java:
import java.util.ArrayList;
public class Breaker implements Runnable{
Long from, to = null;
String name = null;
Thread t = new Thread(this);
public Breaker(String name){
this.name = name;
}
public void scanRange(Long from, Long to){
this.from = from;
this.to = to;
t.start();
}
@Override
public void run() {
this.scan();
}
private void scan() {
ArrayList<ArrayList<Long>> results = new ArrayList<ArrayList<Long>>();
Long startingTime = new Long(System.currentTimeMillis() / 1000L);
Long lastReport = new Long(startingTime);
System.out.println(startingTime + ": Starting number is: " + this.from);
for (Long i = this.from; i <= this.to; i++) {
if (((System.currentTimeMillis() / 1000L) - startingTime ) % 60 == 0 && (System.currentTimeMillis() / 1000L) != lastReport) {
System.out.println((System.currentTimeMillis() / 1000L) + ": " + this.name + " DOING NOW " + i.toString() + ".");
lastReport = (System.currentTimeMillis() / 1000L);
}
ArrayList<Long> a = new ArrayList<Long>();
a = getFriendPair(i);
if(a != null) {
results.add(a);
System.out.println(this.name + ": FOUND PAIR! " + a.toString());
}
}
System.out.println((System.currentTimeMillis() / 1000L) + ": " + this.name + " Done. Total pairs found: " + results.size() +
". Total working time: " + ((System.currentTimeMillis() / 1000L) - startingTime) + " seconds.");
}
/**
* Receives integer and returns an array of the integer and the number who is it's
* pair in case it has any. Else returns null.
* @param i
* @return
*/
private static ArrayList<Long> getFriendPair(Long i) {
Long possibleFriend = getAndSumAllDevisors(i);
if (possibleFriend.compareTo(i) <= 0) return null;
Long sumOfPossibleFriend = getAndSumAllDevisors(possibleFriend);
if(sumOfPossibleFriend.equals(i)) {
ArrayList<Long> pair = new ArrayList<Long>();
pair.add(i);
pair.add(possibleFriend);
return pair;
}
return null;
}
private static Long getAndSumAllDevisors(Long victim) {
Long sum = new Long(1);
Long i = 2L;
Long k = new Long(0);
while ((k = i * i) <= victim) {
if ((victim % i) == 0) {
sum += i;
if (k == victim) return sum;
sum += (victim / i);
}
i++;
}
return sum;
}
}
import java.util.ArrayList;
公共类断路器实现可运行{
Long-from,to=null;
字符串名称=null;
螺纹t=新螺纹(此);
公共断路器(字符串名称){
this.name=名称;
}
公共空间扫描范围(长从、长到){
this.from=from;
这个;
t、 start();
}
@凌驾
公开募捐{
这是scan();
}
专用无效扫描(){
ArrayList结果=新建ArrayList();
长启动时间=新长(System.currentTimeMillis()/1000L);
Long lastReport=新的Long(启动时间);
System.out.println(startingTime+):起始编号为:“+this.from”;
对于(Long i=this.from;i请考虑由线程池支持的ExecutorService。您将it任务馈送给它,当它们可用时,它们将被转移到工作线程:
您需要的是一个“固定线程池”请参阅。我会选择具有固定线程池大小的。您的主线程可以直接提供给executor服务,也可以通过断开连接。阻塞队列的Java文档非常好地描述了生产者-消费者模式。我最终没有回答任何问题,而是接受了Marko的评论,并实现了我的解决方案它的工作和运行速度几乎是未优化版本的两倍
我的代码现在看起来是这样的:
主文件(运行程序)
工作经理
public class runner {
private static Long START_NUM = 1L;
private static Long END_NUM = 10000000L;
public static void main(String[] args) {
Long preciseStartingTime = new Long(System.currentTimeMillis());
ForkJoinPool pool = new ForkJoinPool();
WorkManager worker = new WorkManager(START_NUM, END_NUM);
pool.invoke(worker);
System.out.println("precise time: " + (System.currentTimeMillis() - preciseStartingTime));
}
我在这里定义了3个类变量。from
和to
是从主文件调用的构造函数中设置的。threshold
是程序将分配给单个线程进行串行计算的最大数量。
正如您在代码中看到的,它将递归地使范围变小,直到它小到足以直接计算,然后它调用Breaker开始中断
import java.util.concurrent.RecursiveAction;
public class WorkManager extends RecursiveAction{
Long from, to;
Long threshold = 10000L;
public WorkManager(Long from, Long to) {
this.from = from;
this.to = to;
}
protected void computeDirectly(){
Breaker b = new Breaker(from, to);
b.scan();
}
@Override
protected void compute() {
if ((to - from) <= threshold){
System.out.println("New thread from " + from + " to " + to);
computeDirectly();
}
else{
Long split = (to - from) /2;
invokeAll(new WorkManager(from, from + split),
new WorkManager(from + split + 1L, to));
}
}
}
import java.util.concurrent.RecursiveAction;
公共类WorkManager扩展了RecursiveAction{
从,到,;
长阈值=10000L;
公共工作管理器(长起、长至){
this.from=from;
这个;
}
受保护的void computedDirectly(){
断路器b=新断路器(从,到);
b、 扫描();
}
@凌驾
受保护的void compute(){
如果((to-from)忘记等待和通知,请学习如何使用Fork/Join框架,这与本例完全匹配。有趣的是,您的线程在哪里。我将从断路器本身开始线程(请注意断路器中的第7行和第16行)。同样,不确定这是否是一个好主意。@Tom这很好,但不是很常见。“common”isThread line1=新线程(新的断丝器(“thread1”,1650000L));line1.start();
。这是一个风格问题…@MarkoTopolnik,我现在正在阅读,我可能会同意。如果你能在回答中稍微详细说明一下,我会接受它。
public class Breaker{
Long from, to = null;
public Breaker(Long lFrom, Long lTo) {
this.from = lFrom;
this.to = lTo;
}
public void scan() {
ArrayList<ArrayList<Long>> results = new ArrayList<ArrayList<Long>>();
Long startingTime = new Long(System.currentTimeMillis() / 1000L);
for (Long i = this.from; i <= this.to; i++) {
ArrayList<Long> a = new ArrayList<Long>();
a = getFriendPair(i);
if(a != null) {
results.add(a);
System.out.println((System.currentTimeMillis() / 1000L) + ": FOUND PAIR! " + a.toString());
}
}
}
/**
* Receives integer and returns an array of the integer and the number who is it's
* pair in case it has any. Else returns null.
* @param i
* @return
*/
private static ArrayList<Long> getFriendPair(Long i) {
Long possibleFriend = getAndSumAllDevisors(i);
if (possibleFriend.compareTo(i) <= 0) return null;
Long sumOfPossibleFriend = getAndSumAllDevisors(possibleFriend);
if(sumOfPossibleFriend.equals(i)) {
ArrayList<Long> pair = new ArrayList<Long>();
pair.add(i);
pair.add(possibleFriend);
return pair;
}
return null;
}
private static Long getAndSumAllDevisors(Long victim) {
Long sum = new Long(1);
Long i = 2L;
Long k = new Long(0);
while ((k = i * i) <= victim) {
if ((victim % i) == 0) {
sum += i;
if (k == victim) return sum;
sum += (victim / i);
}
i++;
}
return sum;
}
}