浏览 12214 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-06-12
最后修改:2008-12-30
引用 线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
线程的一些特性:
线程在下列情况之一终止运行:
JVM在下列情况下终止运行:
创建线程: [list] Thread t=new Thread(new Runable(){ public void run(){ //do something } }); [/list] 运行线程:
线程的一些自动继承的特性:
[list] //请等待足够久的时间(可能是1-2分钟),程序会自动停止。 Thread t1=new Thread(){ public void run(){ int i=0; while(true){//死循环 i++; System.out.println(i); //Thread.yield();//如果想让t2有机会更快完成,需要调用yield让出CPU时间。 } } }; t1.setDaemon(true);//注释掉这句就可以看出区别了。 Thread t2=new Thread(){ public void run(){ int i=50000; while(i>0){ i--; } System.out.println("t2 done"); } }; t1.start(); t2.start(); [/list] 线程优先级:
所以,线程的优先级设置是不可靠的,依赖于JVM实现和OS。.NET线程5个等级:Highest,AboveNormal,Normal,BelowNormal,Lowest.Solaris有15个等级,最高的5个等级是给进程中断层级(Process Interrupt Levels ,PILs)使用。也就是说PIL可以中断普通进程知道执行直到其运行结束。剩下的10个优先级可以被线程使用。所以优先级8和9可能并没有区别。默认优先级是5,最大优先级由所在ThreadGroup的maxPriority决定。也就是说所属ThreadGroup最大优先级是8则,以构造函数Thread(ThreadGroup g,String name)所创建的线程即使将其设置为10,优先级仍然是8. public static void main(String[] args) throws Exception { int x=211;//210个线程分3组,每组70个,第211是“发令枪” int n=0;//a类线程数量,本类线程优先级最高 int m=0;//b类线程数量,本类线程优先级最低 int l=0;//c类线程数量,本类线程优先级中间(5) final CyclicBarrier cb=new CyclicBarrier(x);//发令枪类,让所有线程理论上在同一起跑线(也许和逐个逐个start没区别) final List ln=new ArrayList(7);//存放a类线程的列表,为了在匿名类中可见,定义为final,7原本是21个线程在跑,后来为了理论上消除误差,增加到70个,此处没有修改过来。 final List lm=new ArrayList(7);//存放b类线程的列表 final List ll=new ArrayList(7);//存放c类线程的列表 for(int i=0;i<x-1;i++){//为了避免线程在创建的时候同类线程扎堆(理论上可能)产生误差,打乱创建过程。为了避免2组线程分别在双核CPU上各自单核上运行,采用了3组线程。 Runner t=null; if(i%3==0){ t=new Runner(cb,"a"+i); t.setPriority(8);//可以用10,但测试结果看不出区别。 ln.add(t); n++; }else if(i%3==1){ t=new Runner(cb,"b"+i); t.setPriority(2);//可以用1, lm.add(t); m++; }else{ t=new Runner(cb,"c"+i); t.setPriority(5); ll.add(t); l++; } t.start();//不是真的启动线程哦。请看Runner类 } System.out.println(n);//检验是不是每组70个。 System.out.println(m); System.out.println(l); try { Thread.sleep(3000);//本意是为了让Runner在起跑线都预备好,在此停3秒。减少误差。 Timer timer =new Timer(true);//定时打印结果的线程。 timer.scheduleAtFixedRate(new TimerTask(){ @Override public void run() {//定时打印每组线程的结果的平均值,由于打印是有先后顺序的,所以使用平均值,消除时间差(用心良苦啊。。。) System.out.println("a avg--"+getAvg(ln));//可以将a组的结果放在最后,结果通常还是a最慢 System.out.println("b avg--"+getAvg(lm)); System.out.println("c avg--"+getAvg(ll)); } }, 3000, 3000);//3秒打印一次。 cb.await();//发令枪响。 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BrokenBarrierException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("started "); } public static BigInteger getAvg(List l){//为什么用大整数?因为long,和int我都试过得不到想要的结果。 BigInteger total=BigInteger.valueOf(0); for (Iterator iter = l.iterator(); iter.hasNext();) { Runner r = (Runner) iter.next(); total=total.add(r.getCountPerMs()); } return total.divide(BigInteger.valueOf(l.size()));//同组线程的结果的平均值 } static class Runner extends Thread{//有心人可以试试改成只实现Runnable接口 private CyclicBarrier cb; private String name; private BigInteger count=BigInteger.valueOf(0); private long startTime; public Runner(CyclicBarrier cb,String name){ this.cb=cb; this.name=name; } public void run(){ try { cb.await();//让其在起跑线上等待其他线程和发令枪声 System.out.println(this.name+"start");//看看各个线程真正跑起来是否一致,不怕,每组有70条,一条拖后退问题不大,只要运行时间够长,体力好的应该还是不会输在起跑线的。 startTime=System.currentTimeMillis();//原本是为了消除时间差使用的,效果不好,改用发令枪,留着成了僵尸代码 for (;;) { count=count.add(BigInteger.valueOf(1)); Thread.sleep(1);//调试手段,为了使线程慢跑,可以去掉对比结果。 // if(count%10000==0){ // Thread.yield();//调试手段,效果不明显,也毙掉了。 // } // if(count.mod(m)==0){ // String info = name+":"+(count/100000)+"--"+this.getPriority()+"-"+this.isDaemon(); //// System.out.println(info);//早期调试手段,毙掉。 // } } } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } public BigInteger getCountPerMs(){ // long value=System.currentTimeMillis()-startTime; //// System.out.println(value); //// System.out.println("count "+this.count); // if(value==0)return BigInteger.valueOf(0); // return this.count.divide(BigInteger.valueOf(value)); //以上一大段注释掉的代码原本是为了消除时间差的。没啥效果,毙掉 return this.count; } } 结果大大出乎意料,通常a跑得最慢,b跑得最快....... 理论估计:会不会是a优先级高切换太频繁,切换的开销大过运行的开销??,猜测,高手可以指点一下。 结论:不要依赖线程之间的竞争来得到想要的结果。 [/list] 先写到这,下一节开讲线程的使用技巧和设计思想。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-06-12
把A组放在后面统计,我的运行结果如下,A组反而落后于B组
70 70 70 b16start c17start a18start c20start b19start a21start b22start c23start a24start b25start c26start a27start b28start c29start a30start b31start c32start a33start b34start c35start a36start b37start c38start a39start b40start c41start a42start b43start c44start a45start b46start c47start a48start b49start c50start a51start b52start a54start b55start c56start a57start b58start c59start a60start b61start c62start a63start b64start a66start c65start b67start c68start a69start b70start c71start a72start b73start c74start a75start b76start c77start a78start b79start c80start a81start b82start c83start a84start b85start c86start a87start b88start c89start a90start b91start c92start a93start b94start c95start a96start b97start c98start a99start b100start a15start c53start c101start b103start a105start c107start b109start a111start c113start b115start a117start c119start b121start b124start a123start a126start c125start c128start b127start b130start a129start a132start c131start b133start a135start c137start b139start c140start a141start b142start c143start a144start b145start c146start a147start b148start c149start a150start b151start c152start a153start b154start c155start a156start b157start c158start a159start b160start c161start a162start c134start b163start c164start a165start b166start c167start a168start b169start c170start a171start c173start b175start c176start a177start c179start b181start c182start a183start c185start a186start b187start c188start a189start b190start c191start a192start b193start a195start b196start c197start a198start b199start c200start a201start b202start c203start a204start b205start c206start a207start c209start a108start b112start a114start c116start b118start a120start c122start b136start a138start b172start b178start a180start b184start b208start started b1start a0start c2start a3start b4start c5start a6start b7start c8start a9start b10start c11start a12start b13start c14start c194start a174start a102start c104start b106start c110start b avg--94766 c avg--94174 a avg--115073 b avg--224373 c avg--216470 a avg--207931 b avg--341876 c avg--344409 a avg--332709 b avg--466582 c avg--466450 a avg--448567 b avg--659035 c avg--653320 a avg--638056 b avg--784288 c avg--776086 a avg--770561 b avg--908349 c avg--898104 a avg--894808 b avg--1021412 c avg--1026939 a avg--1015154 b avg--1141776 c avg--1147952 a avg--1131192 b avg--1266781 c avg--1270811 a avg--1246034 |
|
返回顶楼 | |
发表时间:2008-06-12
本人INTEL T2050 CPU,双核。系统是WindowsXP
|
|
返回顶楼 | |
发表时间:2008-12-30
这种自己不认真验证的文章真是误人子弟
Thread.currentThread().setDaemon(true) 你倒是设给我看看 引用 /**
* Marks this thread as either a daemon thread or a user thread. The * Java Virtual Machine exits when the only threads running are all * daemon threads. * <p> * This method must be called before the thread is started. * <p> * This method first calls the <code>checkAccess</code> method * of this thread * with no arguments. This may result in throwing a * <code>SecurityException </code>(in the current thread). * * @param on if <code>true</code>, marks this thread as a * daemon thread. * @exception IllegalThreadStateException if this thread is active. * @exception SecurityException if the current thread cannot modify * this thread. * @see #isDaemon() * @see #checkAccess */ public final void setDaemon(boolean on) |
|
返回顶楼 | |
发表时间:2008-12-30
oxromantic 写道 这种自己不认真验证的文章真是误人子弟
Thread.currentThread().setDaemon(true) 你倒是设给我看看 引用 /**
* Marks this thread as either a daemon thread or a user thread. The * Java Virtual Machine exits when the only threads running are all * daemon threads. * <p> * This method must be called before the thread is started. * <p> * This method first calls the <code>checkAccess</code> method * of this thread * with no arguments. This may result in throwing a * <code>SecurityException </code>(in the current thread). * * @param on if <code>true</code>, marks this thread as a * daemon thread. * @exception IllegalThreadStateException if this thread is active. * @exception SecurityException if the current thread cannot modify * this thread. * @see #isDaemon() * @see #checkAccess */ public final void setDaemon(boolean on) 谢谢你的指正。的确是无法修改已启动的用户线程的为守护线程。感谢你那么仔细的阅读拙作 |
|
返回顶楼 | |