[英]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.