该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-07-16
经过测试我发现我写的这个实现还不如java ArrayList 直接遍历相加求和快呢。
数据量大了更是如此吧。 import java.util.ArrayList; import java.util.Random; public class countBasic { public static void main(String[]a){ int index = 100000; ArrayList<Integer> numbers = new ArrayList<Integer>(); ArrayList<RunnableBasic> obj = new ArrayList<RunnableBasic>(); System.out.println("开始生成数组"+System.currentTimeMillis()); for(int i=0;i<1000*100*10;i++){ Random rd = new Random(); int t = rd.nextInt(); numbers.add(t>0?t:0-t); } System.out.println("生成完毕"+System.currentTimeMillis()); ArrayList<Integer> arr = new ArrayList<Integer>(); for(int j =0;j<numbers.size();j++){ arr.add(numbers.get(j)); if((j % index== 0 && j != 0 )|| (j == numbers.size()-1)){ RunnableBasic rb = new RunnableBasic(); rb.vt = new smallBasic(); rb.Numbers = arr; obj.add(rb); arr = new ArrayList<Integer>(); } } ArrayList<Thread> th = new ArrayList<Thread>(); System.out.println("分组完毕"+System.currentTimeMillis()); for(int k = 0 ; k<obj.size();k++){ new Thread(obj.get(k)).start(); } boolean end = false; while(!end){ int m = 0; for(int q=0;q<obj.size();q++){ if(obj.get(q).end.equals("end")){ m++; } } if(m == obj.size()){end = true;} } Sumcenter s = Sumcenter.getInistance(); int sum = 0; for(int u=0;u<s.get().size();u++){ sum += s.get().get(u); } System.out.println("和是:"+sum); System.out.println("计算完毕"+System.currentTimeMillis()); int au = 0; for(int aj =0;aj<numbers.size();aj++){ // System.out.println(numbers.get(aj)); au += numbers.get(aj); } System.out.println("和是:"+au); System.out.println(System.currentTimeMillis()); } } import java.util.ArrayList; public class Sumcenter { public ArrayList<Integer> Brain; private static Sumcenter c; private Sumcenter(){ Brain = new ArrayList<Integer>(); } public static Sumcenter getInistance(){ if(c == null) c = new Sumcenter(); return c; } public void add(int i){ Brain.add(i); } public ArrayList<Integer> get(){ return Brain; } } public class smallBasic { private int sum=0; public void add(int i){ this.sum += i; } public int getSum(){ return this.sum; } } public class RunnableBasic implements Runnable { protected smallBasic vt; protected ArrayList<Integer> Numbers; protected String end =""; public void run() { for(int i=0;i<Numbers.size();i++){ vt.add(Numbers.get(i)); } Sumcenter c = Sumcenter.getInistance(); c.add(vt.getSum()); end = "end"; } } 开始生成数组1279266504921 生成完毕1279266505734 分组完毕1279266505843 和是:-1912057435 计算完毕1279266505875 和是:-1912057435 1279266505890 直接遍历相加所用时间:15 分组遍历多线程在求和所用时间:141 希望大家看看我写的代码哪里出问题了。 |
|
返回顶楼 | |
发表时间:2010-07-16
如果能把整个list放入内存里面,当然是ArrayList内部相加快了。
假设有18个CPU在电脑上面,你直接相加能用到几个CPU? 只有用到一个,因为只有一个线程在运行。那么其他17个CPU就浪费了。 如果分成18个线程相加速度会不会快点。 你写了好多的类,看来看去很复杂。 调用这么多的方法,栈的使用也是很消耗资源的。 不知道你创建了多少个线程。线程也是要资源。所以才导致速度慢。 就说这个代码: for(int u=0;u<s.get().size();u++){ sum += s.get().get(u); } Coding style不好 s我也不知道是什么意思。 s.get()我也不知道返回什么,原来是里面的一个ArrayList。用get做方法名还是很难理解,不能换个名字吗? 然后每次进行u<s.get().size()尽管ArrayList的size()可以马上返回数值,但是你为什么不把size()的值拿到循环外面呢?因为那个值是固定的,没有必要每次比较的时候都去调用一次函数。不知道JIT会不会对你的代码进行了优化,因为那个函数已经访问恩多次的。 然后循环的计数用u?大家都用i j k m等等,没有见过有人用u的。 s.get().get(u)这个也是,相信过1个月之后,你自己看代码也不知道到底拿到的是什么东西了。 我在想为什么你没有同步的代码,原来你是不断的轮询。轮询是很费CPU的时间的。而且你这里面也没有Thread.sleep,这个线程会不断的抢其他线程的计算时间。 while(!end){ int m = 0; for(int q=0;q<obj.size();q++){ if(obj.get(q).end.equals("end")){ m++; } } if(m == obj.size()){end = true;} } 计算开多线程,只要内存够多,尽管多线程之间切换需要一些资源和时间,但是也没有15到141的差距的。 |
|
返回顶楼 | |
发表时间:2010-07-16
hardPass 写道 kakaluyi 写道 mercyblitz 写道 kakaluyi 写道 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; } [color=red]Thread.currentThread().join();[/color] System.out.println("和为:" + MyWorkThread.getSum()); } } 52行Thread.currentThread().join();朋友有个地方不懂,这里Thread.currentThread()是主线程吧,那join()方法就是是主线程等待主线程执行完成,这不是抛出InterruptedException吗 不会,只是会活锁。你可以在main方法里面试试。 经过验证,不是活锁,证明了我的担心,是个死锁 public static void main(String args[]) { try { Thread.currentThread().join(); System.out.println("ok"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } ok永远打印不出来,主线程等待所有子线程结束的方法是不是酱紫地,前面一个同学说了一个方法 atominit方法才是正解 Thread.currentThread().join(); 莫非是传说中的永久sleep,必须等待别人来打断? 它并没有Sleep,而是工作完成之后,在等待。它不能被唤起,传说中的永久sleep应该是Thread#sleep(Long.MAX_VALUE)。 |
|
返回顶楼 | |
发表时间:2010-07-16
最后修改:2010-07-16
我的思路:有一个处理数值相加的类:smallBasic 每个线程会有单独的smallBasic。
线程类RunnableBasic来处理smallBasic的值。Sumcenter来存放每个线程里smallBasic相加的值。最后把每个线程运行求和的结果相加就是整个集合的值。 while(!end){ int m = 0; for(int q=0;q<obj.size();q++){ if(obj.get(q).end.equals("end")){ m++; } } if(m == obj.size()){end = true;} try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } 这段代码我是想等待所用的线程都运行完、然后在去处理每个线程相加的结果。 也不知道还有没有更合适的判断方法。 代码烂、所以时间才会差好多。 |
|
返回顶楼 | |
发表时间:2010-07-16
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(); } join和wait是两码事。join不存在线程之间的唤醒,比如Object#notify操作。并且notify和wait操作,必须在Thread的同步下。而join的意义是wait to die。 join还是有办法打断的,在Thread运行时,报出一个异常就可以把当前线程搞死。 比如: Thread t =new Thread (new Runnable(){ public void run(){ throw new RuntimeException("On purpose!"); } }); t.start(); try { t.join(); } catch (InterruptedException e) { } System.out.println("+++"); |
|
返回顶楼 | |
发表时间:2010-07-16
kakaluyi 写道 mercyblitz 写道 kakaluyi 写道 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; } [color=red]Thread.currentThread().join();[/color] System.out.println("和为:" + MyWorkThread.getSum()); } } 52行Thread.currentThread().join();朋友有个地方不懂,这里Thread.currentThread()是主线程吧,那join()方法就是是主线程等待主线程执行完成,这不是抛出InterruptedException吗 不会,只是会活锁。你可以在main方法里面试试。 经过验证,不是活锁,证明了我的担心,是个死锁 public static void main(String args[]) { try { Thread.currentThread().join(); System.out.println("ok"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } ok永远打印不出来,主线程等待所有子线程结束的方法是不是酱紫地,前面一个同学说了一个方法 atominit方法才是正解 在Java中,死锁应该是指两个线程在同步互斥中,由于释放锁的顺序不当,造成相互等待。而活锁是指,一个线程等待另外一个线程的答复。在这里,Main Thread等待自身(Main Thread)消亡而造成的永久等待,并没有在同步互斥下。因此,我理解为活锁。 |
|
返回顶楼 | |
发表时间:2010-07-16
最后修改:2010-07-16
我尝试了一下。
确实是会导致无限期的等待。 join()方法不应该等待当前的线程,而应该等待其他线程的执行的结束,当然被等待的那个线程必须要可以结束的,不能是while(true) 我也不知道这应该就死锁还是活锁。或者根本就跟锁没有关系。 只是线程的无限期的等待而已。没有任何的同步块或者资源在里面。 跟while(true) { } 是差不多的。 我用了jvisualvm工具之后发现 Thread.currentThread().join();比while的方式还好一点。 就是Thread.currentThread().join();是线程等待,不会有CPU的时间片的执行。 而while是不断的执行时间片。 join的用法参考搜索到的文章 http://deepfuture.iteye.com/blog/599684 |
|
返回顶楼 | |
发表时间:2010-07-16
linchao198401 写道 join()方法不应该等待当前的线程,而应该等待其他线程的执行的结束,当然等待的那个线程必须要可以结束的,不能是 http://deepfuture.iteye.com/blog/599684 你的说法不对,如果是等待其他线程执行结束,那么设计API时候,完全可以把join方法设计成静态方法。 Javadoc上面说了: 引用 Waits for this thread to die.
This thread 就是指本Thread实例。 |
|
返回顶楼 | |
发表时间:2010-07-16
请看看我给的join的例子的链接,看看里面是等谁die。
然后javadoc说的是this thread die。而不是说current thread die. this是通过对象调用的。 当你调用的是thatThread.join(),那么你等的就是thatThread的die。 已经试过currentThread().join()是不会完成就已经知道自己等自己die是不行的了。 |
|
返回顶楼 | |
发表时间:2010-07-16
linchao198401 写道 请看看我给的join的例子的链接,看看里面是等谁die。
然后javadoc说的是this thread die。而不是说current thread die. this是通过对象调用的。 当你调用的是thatThread.join(),那么你等的就是thatThread的die。 已经试过currentThread().join()是不会完成就已经知道自己等自己die是不行的了。 嗯,貌似Thread#currentThread()方法,返回是当前线程,也就是执行Thread#currentThread()语句的方法的线程。 线程有父子关系,你看下Thread#init()方法(被被构造器其调用)。当一个新的线程在start方法调用之前,Thread#currentThread是其父线程,在start方法之中,再调用Thread#currentThread则是其对象本身。 父线程执行完之后,子线程不一定启动。你给的资源中,子线程join之后,该子线程必须等待到die,而这时main方法中,Thread#currentThread()是Main Thread,这个时候调用Thread#currentThread().join()会发生无限期等待。但是,比如在一个方法中,在Thread#currentThread()的join和其他Thread实例start,如果不存在父子关系的话,那么不一定其他Thread实例在调用start方法后也不一定会执行。不知道你是否能够想到这种场景。 总之,Thread对象调用join()方法仅仅让自身等待到die,和其他的线程执行没有关系。 |
|
返回顶楼 | |