Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有wait()/notify()同步的Java合并排序算法_Java_Multithreading_Performance_Concurrency_Mergesort - Fatal编程技术网

带有wait()/notify()同步的Java合并排序算法

带有wait()/notify()同步的Java合并排序算法,java,multithreading,performance,concurrency,mergesort,Java,Multithreading,Performance,Concurrency,Mergesort,我尝试只使用wait/notify同步来实现合并排序。我知道更高级的构造,比如Fork/Join、Executors。等等,但我需要在这里使用工作/通知。基于此,我使用同步块重构了方法parallelMergeSort(): public void parallelMergeSort() { synchronized (values) { if (threadCount <= 1) { mergeSort(values); values.not

我尝试只使用wait/notify同步来实现合并排序。我知道更高级的构造,比如Fork/Join、Executors。等等,但我需要在这里使用工作/通知。基于此,我使用同步块重构了方法
parallelMergeSort()

public void parallelMergeSort() {
  synchronized (values) {
     if (threadCount <= 1) {
        mergeSort(values);
        values.notify();
     } else if (values.length >= 2) {
        // split array in half
       int[] left = Arrays.copyOfRange(values, 0, values.length / 2);
       int[] right = Arrays.copyOfRange(values, values.length / 2, values.length);
       synchronized(left) {
         synchronized (right) {
            // sort the halves
            // mergeSort(left);
            // mergeSort(right);
           Thread lThread = new Thread(new ParallelMergeSort(left, threadCount / 2));
           Thread rThread = new Thread(new ParallelMergeSort(right, threadCount / 2));
           lThread.start();
           rThread.start();
           /*try {
             lThread.join();
             rThread.join();
           } catch (InterruptedException ie) {}*/
           try {
             left.wait();
             right.wait();
           } catch (InterruptedException e) {
             e.printStackTrace();
           }
           // merge them back together
           merge(left, right, values);
        }
      }
      values.notify();
    }
  }
}
public void parallelMergeSort(){
已同步(值){
如果(线程数=2){
//一分为二
int[]left=Arrays.copyOfRange(value,0,value.length/2);
int[]right=Arrays.copyOfRange(value,values.length/2,values.length);
已同步(左){
已同步(右){
//分两半
//合并排序(左);
//合并排序(右);
Thread lThread=新线程(新的并行合并排序(左,threadCount/2));
Thread rThread=新线程(新的ParallelMergeSort(右,threadCount/2));
lThread.start();
rThread.start();
/*试一试{
lThread.join();
rThread.join();
}捕获(中断异常)*/
试一试{
左。等等();
对,等等;
}捕捉(中断异常e){
e、 printStackTrace();
}
//将它们合并在一起
合并(左、右、值);
}
}
value.notify();
}
}
}
是此处的输入数组


因此,我看到排序的性能下降了,甚至比单线程排序还要慢。我猜一个瓶颈是在一个数组的左右部分的两个同步块内。有人知道如何重构它以使其比单线程排序更快吗?

如果你知道的话,你将需要对数百万个值进行排序以查看并行性的效果,因为你正在到处复制数组,这会使系统在内存访问和垃圾收集方面承受最大的压力,不在分拣机上

要正确地并行排序,您需要在适当的位置执行它——这使得合并排序不太可能是一个好的候选排序,因为它必须为目标创建一个新数组

如果你所做的只是实验,那么就使用比较/计算密集型算法,比如冒泡排序


请注意,如果已将其设置为作业,则讲师可能希望您回答“您不能”,因为合并排序不适合并行性。

问题在于嵌套的
同步的
块:

synchronized(left) {
   synchronized (right) {
       Thread lThread = new Thread(…);
       Thread rThread = new Thread(…);
       lThread.start();
       rThread.start();
       try {
         left.wait();
         right.wait();
       }
       …
当您启动新线程时,您持有这两个锁,而新线程又试图获取这些锁。因此,新线程将被阻止,直到启动线程释放这些锁。当线程调用
wait()
但是…一次只能等待一个条件时,就会隐式发生这种情况

因此,当启动线程调用
left.wait()
时,它会释放
left
实例的锁,并且为处理
left
部分而生成的子线程可以继续,但启动线程在等待
left
时仍然持有
right
锁。一旦子线程完成对
left
的处理,它将调用
notify
,然后释放
left
的锁,该锁允许
wait()
重新获取它并返回

然后,启动线程可以调用
right.wait()
,这将释放
right
锁,并允许另一个子线程开始其工作,因此相当于顺序性能。对于每个子线程的繁殖,由于启动线程持有的锁,子线程被强制一个接一个地运行

解决此问题的一种方法是首先启动线程,然后获取锁,并且只获取一个将要等待的锁,而不是嵌套
已同步的
块。这仍然受制于未指定的计时(现在,即使在您进入
synchronized(x){x.wait();}
块之前,子线程可能已经完成了其工作并调用了
notify
)和所谓的伪唤醒。简单地说,您需要一个可验证的条件,该条件在调用
wait()
之前和之后都会被检查,如下所述:

与单参数版本一样,中断和虚假唤醒是可能的,并且此方法应始终在循环中使用:

synchronized (obj) {
    while (<condition does not hold>)
        obj.wait();
    ... // Perform action appropriate to condition
}
synchronized(obj){
而()
obj.wait();
…//执行适合条件的操作
}
该条件可能是子线程在调用
notify()
以发出工作已完成的信号之前,将
boolean
标志设置为
true


请注意,这些都是使用
Thread.join()
时免费获得的。同步发生在
join()
方法中,这两个调用不能重叠。此外,该实现使用可验证的条件(线程的活动状态)来确保仅在必要时调用
wait()
,并保护自身免受“虚假唤醒”的影响。

为什么要同步左右阵列?其思想是,每个线程对数组的另一部分进行排序,因此不需要同步。@Fank但我需要等待这些线程,然后再合并左右部分,wait()应该在同步部分中。@kolya我认为wait()在这里不是特别有用。当一个线程想要访问可能被另一个线程锁定的资源时,使用Wait。并行算法试图通过同时处理数据的不同部分来避免这种情况。你想要的可能是加入。等待/通知机制在需要互斥或信号量时非常有用,如供应商/消费者问题。使用
left.Wait()
right.Wait()
是错误的<代码>o.等待()