簡體   English   中英

Java中的多線程-4個自動執行相同操作的線程

[英]Multithreading in java - 4 threads that do the same automatically

我編寫了一個程序來掃描友好數字(一個2個數字對,一個對數的所有除數之和等於另一個)。它工作正常,我將在下面包括整個代碼。 我試圖使其與多個線程一起運行,因此將代碼移至名為Breaker的類,其主要外觀如下:

    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),並在線程結束時觸發下一個節,直到整個主范圍完成。

我試過理解如何使用synced,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;
}
}

考慮由線程池支持的ExecutorService。 您向它提供任務,並且它們在可用時會被改編到工作線程中:

http://www.vogella.com/articles/JavaConcurrency/article.html#threadpools

我會選擇具有固定線程池大小的ExecutorService 您的主線程可以直接提供給執行程序服務,也可以通過BlockingQueue斷開它們的連接。 阻塞隊列的Java文檔很好地描述了生產者-消費者模式。

我最終沒有選擇答案,而是選擇Marko的評論,並使用Fork / Join框架實現了我的解決方案。 它的工作和運行速度幾乎是未優化版本的兩倍。

我的代碼現在看起來像這樣:

主文件(運行器)

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));
}

WorkManager中

我在這里定義了3個類變量。 fromto是從從主文件調用的構造函數中設置的。 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));
    }
}
}

破壞者 (不再是Runnable的實現)

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;
}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM