该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-07-14
star022 写道 fork/join处理这个貌似是最合适的-----晕,一不小心发重复了,修改一下,顺便发个相关链接:
http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/ 这篇文章不错,谢了。 按照这个思路,其实子线程也可以分组求和最后再求和的,这样可能更快。 |
|
返回顶楼 | |
发表时间:2010-07-14
高手还是很多的,哈哈,这个帖子有意思
|
|
返回顶楼 | |
发表时间:2010-07-14
linliangyi2007 写道 高手还是很多的,哈哈,这个帖子有意思 嗯。。很多高手,关键时候都出来了。 |
|
返回顶楼 | |
发表时间:2010-07-14
为什么要先分好呢? 而且这里线程数是否可以动态变化?
我意思让线程自己去BigList中去取数, 加完再取, 这样无论多少个线程, 也不会出现等待的情况, 直道再取不出数了即可. 又或者, 从bigList中每次取两个, 相加完成后放回bigList(可以把list构造成栈,FIFO), 这样无论多少线程,都好用了 |
|
返回顶楼 | |
发表时间:2010-07-14
Joo 写道 为什么要先分好呢? 而且这里线程数是否可以动态变化?
我意思让线程自己去BigList中去取数, 加完再取, 这样无论多少个线程, 也不会出现等待的情况, 直道再取不出数了即可. 又或者, 从bigList中每次取两个, 相加完成后放回bigList(可以把list构造成栈,FIFO), 这样无论多少线程,都好用了 你说的意思应该是阻塞队列的那种情况,不过这样也有等待,当其中一个线程去取值的时候,其他的线程就要等着。 分割是为了分配任务,就像大家都敢一个活,你做这点,我做这点,咱俩互不影响,都干完了活也就完了。 |
|
返回顶楼 | |
发表时间:2010-07-14
hardPass 写道 package com.wl.test.concurrent.semaphore; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; /** * * 有一个很大的整数list,需要求这个list中所有整数的和,写一个可以充分利用多核CPU的代码,来计算结果。 * * * 乍一看到题目“充分利用多核CPU”, * 以为会根据CPU的核心数,计算出比较合理的任务线程的数目。 * 就题目的计算目标来说,实际上讲的主线程等待任务线程完成, * 任务线程之间没有必要互相等待。 * 是不是可以考虑用信号来...... * 每次来看帖,都发现大家图画的很拉风…… * * 我也帖个代码,虽然来晚了,大家不一定能看到…… * * @author HardPass * */ public class BigListSumWithSemaphore { private List<Integer> list = new ArrayList<Integer>(); private AtomicLong sum = new AtomicLong(0L); // 结果 private int threadCounts = 2 * Runtime.getRuntime().availableProcessors() + 1; // 任务线程数 private List<Runnable> tasks = new ArrayList<Runnable>(); // 任务线程 SemaphoreLock lock = new SemaphoreLock(); public static void main(String[] args) { new BigListSumWithSemaphore().test(); } public void test() { init(); ExecutorService exec = Executors.newFixedThreadPool(threadCounts); //线程池 for(Runnable task : tasks){ exec.execute(task); } lock.lockHere(); // 此处尝试wait exec.shutdown(); System.out.println("List中所有整数的和为:" + sum); } private void init() { for (int i = 1; i <= 1000000; i++) { list.add(i); } int len = list.size() / threadCounts; int i = 0; for (; i < threadCounts - 1; i++) { tasks.add(new Task(list.subList(i * len, (i + 1) * len))); } tasks.add(new Task(list.subList(i * len, list.size()))); } private class Task implements Runnable { private List<Integer> subList; public Task(List<Integer> subList) { this.subList = subList; } @Override public void run() { lock.lockThere(); // 增加锁的计数 long subSum = 0L; for (Integer i : subList) { subSum += i; } sum.addAndGet(subSum); System.out.println("分配给线程:" + Thread.currentThread().getName() + "那一部分List的整数和为:\tSubSum:" + subSum); lock.release(); // 释放一个锁的计数 } } } /** * * 信号量锁 * * 此Semaphore非java.util.concurrent.Semaphore * * @author HardPass * */ class SemaphoreLock { private int count = 0; // 信号量 /** * 信号量大于0的时候 wait * 这是不是传说中的可重入? */ public synchronized void lockHere() { while (count > 0) { try { wait(); } catch (InterruptedException e) { } } } public synchronized void lockThere() { count++; } public synchronized void release() { count--; if(count==0){ notify(); } } } 对这个进行100次测试,发现有时候算出来的答案不正确,最后一个线程的结果没有累加进去,,, 5分配给线程:pool-1-thread-3那一部分List的整数和为: SubSum:100000100000 5分配给线程:pool-1-thread-1那一部分List的整数和为: SubSum:20000100000 5分配给线程:pool-1-thread-2那一部分List的整数和为: SubSum:60000100000 5分配给线程:pool-1-thread-4那一部分List的整数和为: SubSum:140000100000 ===List中所有整数的和为:320000400000threadCounts:5 5分配给线程:pool-1-thread-5那一部分List的整数和为: SubSum:180000100000 代码: sum.addAndGet(subSum); System.out.println("分配给线程:" + Thread.currentThread().getName() + "那一部分List的整数和为:\tSubSum:" + subSum); lock.release(); // 释放一个锁的计数 这个存在问题的? 代码理论由上往下执行,这个什么时候可能存在这样问题?(以前看单例双重检查加锁,new语句开辟内存区,但还未初始化数据,类似的?) |
|
返回顶楼 | |
发表时间:2010-07-14
最后修改:2010-07-14
使用Gedit编辑的,难免有语法错误,呵呵
我的一个解法: public class MyWorkThread extends Thread { private static BigDecimal sum; private List<Integer> list; private int start, end; private long value; public static BigDecimal getSum() { return sum; } public static synchronized void addSum(long v) { if (sum == null) { sum = new BigDecimal(v); } else { sum.add(BigDecimal.valueOf(v)); } } public MyWorkThread(List<Integer> list, Integer start, Integer end) { this.list = list; this.start = start; this.end = end; } private void add(int v) { if (Long.MAX_VALUE - v > value) { value += v; } else { addSum(value); value = v; } } public void run() { for(int i = start; i < end; i++) add(list.get(i)); } public static void main(String[] args) throws InterruptedException { List<Integer> list = new ArrayList<Integer>(); int cpuCoreSize = 2; int len = list.size() / cpuCoreSize; int start = 0, end = len; for (;;) { end = start + len; if (end > list.size()) end = list.size(); new MyWorkThread(list, start, end).start(); start = end; if (start == list.size()) break; } Thread.currentThread().join(); System.out.println("和为:" + MyWorkThread.getSum()); } } |
|
返回顶楼 | |
发表时间:2010-07-14
skzr.org 写道 使用Gedit编辑的,难免有语法错误,呵呵
我的一个解法: public class MyWorkThread extends Thread { private static BigDecimal sum; private List<Integer> list; private int start, end; private long value; public static BigDecimal getSum() { return sum; } public static synchronized void addSum(long v) { if (sum == null) { sum = new BigDecimal(v); } else { sum.add(BigDecimal.valueOf(v)); } } public MyWorkThread(List<Integer> list, Integer start, Integer end) { this.list = list; this.start = start; this.end = end; } private void add(int v) { if (Long.MAX_VALUE - v > value) { value += v; } else { addSum(value); value = v; } } public void run() { for(int i = start; i < end; i++) add(list.get(i)); } public static void main(String[] args) throws InterruptedException { List<Integer> list = new ArrayList<Integer>(); int cpuCoreSize = 2; int len = list.size() / cpuCoreSize; int start = 0, end = len; for (;;) { end = start + len; if (end > list.size()) end = list.size(); new MyWorkThread(list, start, end).start(); start = end; if (start == list.size()) break; } Thread.currentThread().join(); System.out.println("和为:" + MyWorkThread.getSum()); } } 这个做法和楼主的差不多,在Java Collection,List#sublist方法,会创建一个新的java.util.SubList和它的子类,也是利用的偏移量来做的。 这里完全没有必要使用同步,使用AtomicLong就行了,如果大List是一个ArrayList的话,一个足够了,如果是LinkedList的实现,多个AtomicLong就行了。这里顺序不重要,利用Atomic*的内存CAS操作即可。 |
|
返回顶楼 | |
发表时间:2010-07-14
很有意义的帖子,看来JE里真是卧虎藏龙啊,呵呵
|
|
返回顶楼 | |
发表时间:2010-07-14
最后修改:2010-07-14
dien 写道 hardPass 写道 package com.wl.test.concurrent.semaphore; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; /** * * 有一个很大的整数list,需要求这个list中所有整数的和,写一个可以充分利用多核CPU的代码,来计算结果。 * * * 乍一看到题目“充分利用多核CPU”, * 以为会根据CPU的核心数,计算出比较合理的任务线程的数目。 * 就题目的计算目标来说,实际上讲的主线程等待任务线程完成, * 任务线程之间没有必要互相等待。 * 是不是可以考虑用信号来...... * 每次来看帖,都发现大家图画的很拉风…… * * 我也帖个代码,虽然来晚了,大家不一定能看到…… * * @author HardPass * */ public class BigListSumWithSemaphore { private List<Integer> list = new ArrayList<Integer>(); private AtomicLong sum = new AtomicLong(0L); // 结果 private int threadCounts = 2 * Runtime.getRuntime().availableProcessors() + 1; // 任务线程数 private List<Runnable> tasks = new ArrayList<Runnable>(); // 任务线程 SemaphoreLock lock = new SemaphoreLock(); public static void main(String[] args) { new BigListSumWithSemaphore().test(); } public void test() { init(); ExecutorService exec = Executors.newFixedThreadPool(threadCounts); //线程池 for(Runnable task : tasks){ exec.execute(task); } lock.lockHere(); // 此处尝试wait exec.shutdown(); System.out.println("List中所有整数的和为:" + sum); } private void init() { for (int i = 1; i <= 1000000; i++) { list.add(i); } int len = list.size() / threadCounts; int i = 0; for (; i < threadCounts - 1; i++) { tasks.add(new Task(list.subList(i * len, (i + 1) * len))); } tasks.add(new Task(list.subList(i * len, list.size()))); } private class Task implements Runnable { private List<Integer> subList; public Task(List<Integer> subList) { this.subList = subList; } @Override public void run() { lock.lockThere(); // 增加锁的计数 long subSum = 0L; for (Integer i : subList) { subSum += i; } sum.addAndGet(subSum); System.out.println("分配给线程:" + Thread.currentThread().getName() + "那一部分List的整数和为:\tSubSum:" + subSum); lock.release(); // 释放一个锁的计数 } } } /** * * 信号量锁 * * 此Semaphore非java.util.concurrent.Semaphore * * @author HardPass * */ class SemaphoreLock { private int count = 0; // 信号量 /** * 信号量大于0的时候 wait * 这是不是传说中的可重入? */ public synchronized void lockHere() { while (count > 0) { try { wait(); } catch (InterruptedException e) { } } } public synchronized void lockThere() { count++; } public synchronized void release() { count--; if(count==0){ notify(); } } } 对这个进行100次测试,发现有时候算出来的答案不正确,最后一个线程的结果没有累加进去,,, 5分配给线程:pool-1-thread-3那一部分List的整数和为: SubSum:100000100000 5分配给线程:pool-1-thread-1那一部分List的整数和为: SubSum:20000100000 5分配给线程:pool-1-thread-2那一部分List的整数和为: SubSum:60000100000 5分配给线程:pool-1-thread-4那一部分List的整数和为: SubSum:140000100000 ===List中所有整数的和为:320000400000threadCounts:5 5分配给线程:pool-1-thread-5那一部分List的整数和为: SubSum:180000100000 代码: sum.addAndGet(subSum); System.out.println("分配给线程:" + Thread.currentThread().getName() + "那一部分List的整数和为:\tSubSum:" + subSum); lock.release(); // 释放一个锁的计数 这个存在问题的? 代码理论由上往下执行,这个什么时候可能存在这样问题?(以前看单例双重检查加锁,new语句开辟内存区,但还未初始化数据,类似的?) 没这么复杂 应该是主线程执行太快,任务线程还没来得及锁导致的。 这个东西本来是想模拟CountDownLatch的 仔细想了下,这个设计还会有很大的问题,如果其中某个或者某些任务线程起的太快,并且完成的也快,会导致锁计数很快增加并很快减为0,并且在这个时候,还有一些任务线程还没有启动…… 解决方法也不是没有,可以将加锁放在主线程,任务线程只release^ 还是用CountDownLatch 比较稳妥 ExecuteService invokeall callable 也是推荐的方法 |
|
返回顶楼 | |