该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-07-15
如果只是考CyclicBarrier的使用,那没接触过的人不就不会了.
|
|
返回顶楼 | |
发表时间:2010-07-15
最后修改:2010-07-15
仔细研究了下Thread.currentThread().join();
当前线程等待当前线程结束? while (isAlive()) { wait(0); } 实际上是当前线程等待自己die:因为一直等待,所以无法die;因为没有die,所以还在wait(0) 如果企图在其他线程Notify,会报java.lang.IllegalMonitorStateException,同时,它还在无限制的等待自己die 所以这个代码非常恶劣霸道! 会导致当前线程永久性地睡眠,并且没有任何办法打断。 final Thread mainThread = Thread.currentThread(); Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("------"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("------"); mainThread.notify(); } }); t.start(); try { //t.join(); //Thread.currentThread().join(1000); Thread.currentThread().join(); System.out.println("++"); } catch (InterruptedException e) { e.printStackTrace(); } |
|
返回顶楼 | |
发表时间:2010-07-15
我觉得还可以优化下
public static BigInteger g(List<Integer> list, int k) throws InterruptedException { int size = list.size(); if (size == 0 || k < 1) { throw new RuntimeException(); } k = k <= size ? k : size; int a = (size + k - 1) / k; Test[] t = new Test[k - 1]; for (int i = 0; i < t.length; i++) { t[i] = new Test(list.subList(a * i, a * i + a)); t[i].start(); } Test c = new Test(list.subList(a * (k - 1), size)); c.run(); BigInteger sum = c.sum; for (int i = 0; i < t.length; i++) { t[i].join(); sum = sum.add(t[i].sum); } return sum; } private static class Test extends Thread { public Test(List<Integer> list) { this.list = list; sum = BigInteger.ZERO; _sum = 0; } @Override public void run() { for (Integer i : list) { if (i == 0) { continue; } if (i > 0 ? (_sum + i < _sum) : (_sum + i > _sum)) { sum = sum.add(BigInteger.valueOf(_sum)); _sum = 0; } _sum += i; } sum = sum.add(BigInteger.valueOf(_sum)); } private List<Integer> list; private BigInteger sum; private long _sum; } |
|
返回顶楼 | |
发表时间:2010-07-15
lucky16 写道 hrsvici412 写道 学到好多线程的东西,请问 你的分析的图,是用什么工具画的!
好像是office2007or2010 里面有一个好像就叫流程图的东西~ 是指的visio吗?画流程图没问题,就是不太好看,没有楼主的那么艳丽 |
|
返回顶楼 | |
发表时间:2010-07-15
hardPass 写道 仔细研究了下Thread.currentThread().join();
当前线程等待当前线程结束? while (isAlive()) { wait(0); } 实际上是当前线程等待自己die:因为一直等待,所以无法die;因为没有die,所以还在wait(0) 如果企图在其他线程Notify,会报java.lang.IllegalMonitorStateException,同时,它还在无限制的等待自己die 所以这个代码非常恶劣霸道! 会导致当前线程永久性地睡眠,并且没有任何办法打断。 final Thread mainThread = Thread.currentThread(); Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("------"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("------"); mainThread.notify(); } }); t.start(); try { //t.join(); //Thread.currentThread().join(1000); Thread.currentThread().join(); System.out.println("++"); } catch (InterruptedException e) { e.printStackTrace(); } 嗯。。相互等待,死锁。。 |
|
返回顶楼 | |
发表时间:2010-07-15
本质上是一个分治思想,google的map/reduce也是这么个意思。但是有个问题,以前我们在实际运用中使用类似的方案时,发现服务器的CPU并不是都在忙碌状态中,也就是说Java的多线程技术并不是一定能够充分利用到服务器的所有CPU资源。具体原因还不得而知,我怀疑是jvm的底层实现造成的。毕竟UNIX系统根本就没有线程的概念。还望有大牛能够解释一下,谢谢
|
|
返回顶楼 | |
发表时间:2010-07-15
使用ExecutorService.invokeAll的缺点是,如果第一个任务需要花很多时间,可能不得不等待
使用这个会一个一个的遍历,如果某个任务还没有完成就会等待 应该使用ExecutorCompleteionService,会直接获取下一个已经完成的task,如果没有任何一个task是完成的话,再等待。 |
|
返回顶楼 | |
发表时间:2010-07-15
最后修改:2010-07-15
lanxiazhi 写道 看过主贴和评论,学习了。
发现的问题: (1)CyclicBarrier不适合这种并发任务。单个线程完成任务之后完全可以终止了,没必要全部等待着,这可能是很大的资源浪费。使用CountDownLatch也会有这个问题。 (2)楼主使用了线程同步,考虑到同步的代价,这是可能是个很大的时间浪费。 (3)楼主使用CyclicBarrier的唯一用处在于,保证所有的任务都完成了。但是杀鸡焉用牛刀?这可能是...的浪费 其实实现这样的功能,可以不用那么复杂,而且可以不用加锁。这里需要一个AtomicInteger(设为atom)。每个线程获得自己的sublist求和任务之后,计算一个和,保存到某个成员变量(设为subsum)中(如某楼上所说),把那个atom加1,然后结束。 在主方法中,启动所有线程,然后添加一条语句,等待所有线程完成任务: while(atom.intValue()<threadCounts) Thread.yield(); 最后从所有死掉的线程对象中,获取subsum并累加即可。 我比较同意lanxianzhi的说法。 使用CountDownLatch,其他所有的计算线程都在计算,最后输出的线程肯定在等所有的线程算好才行。 更进一步的问题是:如果我想知道目前算好的实时总数是多少,以及目前多少个线程已经算好了,那么使用CountDownLatch是没有办法的。 比如,有10000个计算线程,一个输出线程在wait,输出线程只能等10000个计算线程都计算完,wait才会结束,然后才能输出。只有一次输出。 也许你想在计算的线程里面把目前被同步的sum给实时打印出来,这样每个计算线程计算结束之后就把当时的实时的结果打印出来,那么计算线程就不符合单一责任原则了。 对于目前已经完成多少个任务,再加个线程共享的变量(任务完成计数器)来自增也不好。 就算用上AtomicInteger也是一种负担。 所以我不觉得应该使用CountDownLatch 线程同步synchronized是不需要的,用AtomicInteger会快一些。 CyclicBarrier就更不需要了,我没有写代码测试,但是按照我的理解,如果你开启11个线程,10个线程在计算,1个线程等待输出,只有当所有线程都执行到await()才能继续。 如果你开的线程就上千个,那么且不是上千个线程都在那边等待? 我还是推荐使用ExecutorCompleteionService 1. ExecutorCompleteionService可以随时拿到完成计算的线程的结果,然后在这个基础上继续进行加运算,而且不需要创建一个在线程之间共享的变量,每个线程有自己的结果变量,这个变量最终会作为task的结果之一返回。 2. 可以随时知道完成的计算线程的计数,当然需要ExecutorCompleteionService执行够快才行,如果计算线程执行很快就结束的话,完成的线程数会不准 我没有在机子上试 贴个Java核心技术的例子代码 ExecutorCompleteionService service = new ExecutorCompleteionService(executor); for(Callable<Integer> task : tasks) { service.submit(task); } for(int i = 0; i < tasks.size(); i++) { count += service.take().get();// 如果有线程返回,马上可以得到结果,如果没有任何线程返回,阻塞等待结果 } 这里不需要sum这个所有的线程都共享的变量。因此也不需要同步或者AtomicInteger。 |
|
返回顶楼 | |
发表时间:2010-07-16
linchao198401 写道 lanxiazhi 写道 看过主贴和评论,学习了。
发现的问题: (1)CyclicBarrier不适合这种并发任务。单个线程完成任务之后完全可以终止了,没必要全部等待着,这可能是很大的资源浪费。使用CountDownLatch也会有这个问题。 (2)楼主使用了线程同步,考虑到同步的代价,这是可能是个很大的时间浪费。 (3)楼主使用CyclicBarrier的唯一用处在于,保证所有的任务都完成了。但是杀鸡焉用牛刀?这可能是...的浪费 其实实现这样的功能,可以不用那么复杂,而且可以不用加锁。这里需要一个AtomicInteger(设为atom)。每个线程获得自己的sublist求和任务之后,计算一个和,保存到某个成员变量(设为subsum)中(如某楼上所说),把那个atom加1,然后结束。 在主方法中,启动所有线程,然后添加一条语句,等待所有线程完成任务: while(atom.intValue()<threadCounts) Thread.yield(); 最后从所有死掉的线程对象中,获取subsum并累加即可。 我比较同意lanxianzhi的说法。 使用CountDownLatch,其他所有的计算线程都在计算,最后输出的线程肯定在等所有的线程算好才行。 更进一步的问题是:如果我想知道目前算好的实时总数是多少,以及目前多少个线程已经算好了,那么使用CountDownLatch是没有办法的。 比如,有10000个计算线程,一个输出线程在wait,输出线程只能等10000个计算线程都计算完,wait才会结束,然后才能输出。只有一次输出。 也许你想在计算的线程里面把目前被同步的sum给实时打印出来,这样每个计算线程计算结束之后就把当时的实时的结果打印出来,那么计算线程就不符合单一责任原则了。 对于目前已经完成多少个任务,再加个线程共享的变量(任务完成计数器)来自增也不好。 就算用上AtomicInteger也是一种负担。 所以我不觉得应该使用CountDownLatch 线程同步synchronized是不需要的,用AtomicInteger会快一些。 CyclicBarrier就更不需要了,我没有写代码测试,但是按照我的理解,如果你开启11个线程,10个线程在计算,1个线程等待输出,只有当所有线程都执行到await()才能继续。 如果你开的线程就上千个,那么且不是上千个线程都在那边等待? 我还是推荐使用ExecutorCompleteionService 1. ExecutorCompleteionService可以随时拿到完成计算的线程的结果,然后在这个基础上继续进行加运算,而且不需要创建一个在线程之间共享的变量,每个线程有自己的结果变量,这个变量最终会作为task的结果之一返回。 2. 可以随时知道完成的计算线程的计数,当然需要ExecutorCompleteionService执行够快才行,如果计算线程执行很快就结束的话,完成的线程数会不准 我没有在机子上试 贴个Java核心技术的例子代码 ExecutorCompleteionService service = new ExecutorCompleteionService(executor); for(Callable<Integer> task : tasks) { service.submit(task); } for(int i = 0; i < tasks.size(); i++) { count += service.take().get();// 如果有线程返回,马上可以得到结果,如果没有任何线程返回,阻塞等待结果 } 这里不需要sum这个所有的线程都共享的变量。因此也不需要同步或者AtomicInteger。 lanxianzhi说的不错,那段代码却是存在这些问题。在这个场景中CyclicBarrier不合适,他应该用在更灵活的控制中。 TO linchao198401。ExecutorCompleteionService我试了,他的优越之处在于实时性,而invokeAll()方法要等待所有的任务全部完成或者超时时才返回。 |
|
返回顶楼 | |
发表时间:2010-07-16
实现原理非常清除,顶!
|
|
返回顶楼 | |