簡體   English   中英

多線程改組數組

[英]Shuffling array in multiple threads

我有一個大小為N的數組。我想在2個線程(或更多個線程)中將其元素改組。 每個線程都應該使用它自己的數組部分。

可以說,第一個線程將元素從0到K隨機排序,第二個線程將元素從K到N隨機排序(其中0 <K <N)。 因此,它看起來可能像這樣:

//try-catch stuff is ommited
static void shuffle(int[] array) {
   Thread t1 = new ShufflingThread(array, 0, array.length / 2);
   Thread t2 = new ShufflingThread(array, array.length / 2, array.length);
   t1.start();
   t2.start();
   t1.join();
   t2.join();
}

public static void main(String[] args) {
   int array = generateBigSortedArray();
   shuffle(array);
}

經過這樣的改組后,JVM是否有任何保證,使我可以從main方法看到array更改?

為了獲得這樣的保證,我應該如何實現ShufflingThread (或者,應該如何在synchronized塊中或其他地方運行它)?

join()調用足以確保內存一致性:當t1.join()返回時,主線程“看到”線程t1對數組所做的任何操作。

而且,Java保證在數組上不存在單詞撕裂:不同的線程可以使用同一數組的不同元素而無需同步。

我認為這是線程控制中的一個很好的練習,其中(1)可以將一項工作分解成幾個部分(2)這些部分可以獨立和異步運行,並且(3)主線程監視所有此類任務的完成情況各自的線程。 您需要的是,每次線程完成執行時,此主線程都可以wait()並獲得notify()-ed jobCount次。 這是您可以編譯/運行的示例代碼。 取消注釋println()以查看更多信息。

注意:[1] JVM不保證線程的執行順序。[2]當主線程訪問大數組時,您需要進行同步,以免損壞數據。

公共類ShufflingArray {

private int nPart = 4,      // Count of jobs distributed, resource dependent
        activeThreadCount,  // Currently active, monitored with notify
        iRay[];         // Array the threads will work on

    public ShufflingArray (int[] a) {
    iRay = a;
    printArray (a);
}

private void printArray (int[] ia) {
    for (int i = 0 ; i < ia.length ; i++)
        System.out.print (" " + ((ia[i] < 10) ? " " : "") + ia[i]);
    System.out.println();
    }

public void shuffle () {
    int startNext = 0, pLen = iRay.length / nPart;  // make a bunch of parts
    for (int i = 0 ; i < nPart ; i++, activeThreadCount++) {
        int start = (i == 0) ? 0 : startNext,
            stop = start + pLen;
        startNext = stop;
        if (i == (nPart-1))
            stop = iRay.length;
        new Thread (new ShuffleOnePart (start, stop, (i+1))).start();
    }
    waitOnShufflers (0);        // returns when activeThreadCount == 0
    printArray (iRay);
}

synchronized private void waitOnShufflers (int bump) {
    if (bump == 0) {
        while (activeThreadCount > 0) {
            // System.out.println ("Waiting on " + activeThreadCount + " threads");
            try {
                wait();
            } catch (InterruptedException intex) {
    }}} else {
        activeThreadCount += bump;
        notify();
}}

public class ShuffleOnePart implements Runnable {
    private int startIndex, stopIndex;      // Operate on global array iRay

    public ShuffleOnePart (int i, int j, int k) {
        startIndex = i;
        stopIndex = j;
        // System.out.println ("Shuffler part #" + k);
    }

    // Suppose shuffling means interchanging the first and last pairs
    public void run () {
        int tmp = iRay[startIndex+1];
        iRay[startIndex+1] = iRay[startIndex];  iRay[startIndex] = tmp;
        tmp = iRay[stopIndex-1];
        iRay[stopIndex-1] = iRay[stopIndex-2];  iRay[stopIndex-2] = tmp;
        try {   // Lets imagine it needs to do something else too
            Thread.sleep (157);
        } catch (InterruptedException iex) { }
        waitOnShufflers (-1);
}}

public static void main (String[] args) {
    int n = 25, ia[] = new int[n];
    for (int i = 0 ; i < n ; i++)
        ia[i] = i+1;
    new ShufflingArray(ia).shuffle();

}}

Thread.start()和Thread.join()足以讓您在數組初始化,將其移交給線程以及在main方法中進行回讀之間發生事前關聯。

導致事前發生的操作在此處記錄

正如其他地方提到的,ForkJoin非常適合這種分而治之算法,使您擺脫了許多本來需要實現的記賬工作。

將java.util.Concurrent包中的ExecutorService與Callable Task一起使用,以從每個線程運行返回數組的一部分,一旦兩個線程都完成,則這是保持行為一致的另一種方法。

好吧,它們不能同時訪問同一數組,並且如果您使用鎖,互斥鎖或任何其他同步機制,則可能會丟失線程的功能(因為一個線程必須等待另一個線程才能完成操作)改組或完成一些改組)。 為什么不將數組分成兩半,為每個線程分配其數組的位,然后合並兩個數組?

暫無
暫無

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

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