标签:
前言
Java的部分有基础、设计模式、IO、NIO、多线程,之后有时间还会把集合这部分补上去,这么多内容里面,难免有一些知识点遗漏,本文主要是讲解这些遗漏的知识点。这些知识点,不是特别大的难点,所以没有必要专门写一篇文章讲解;但是这些知识点,也不是一两句话就说得清楚的,所以放在这里。本文和前面的代码优化、类继承接口实现一样,也是一篇长期更新的文章,只要想到有遗漏的知识点,就会随时更新此文。
Thread.sleep(XXX)方法消耗CPU吗?
这个知识点是我之前认识一直有错误的一个知识点,在我以前的认识里面,我一直认为Thread.sleep(1000)的这一秒钟的时间内,线程的休眠是一直占用着CPU的时间片休眠的,查看了资料和仔细思考之后发现不是。Thread.sleep(1000)的意思是:代码执行到这儿,1秒钟之内我休息一下,就不参与CPU竞争了,1秒钟之后我再过来参与CPU竞争。
说到这儿,就要顺便再提sleep和wait的区别了,JDK源码提供给我们的注释是非常严谨的:
1 /** 2 * Causes the currently executing thread to sleep (temporarily cease 3 * execution) for the specified number of milliseconds, subject to 4 * the precision and accuracy of system timers and schedulers. The thread 5 * does not lose ownership of any monitors. 6 * 7 * @param millis the length of time to sleep in milliseconds. 8 * @exception InterruptedException if any thread has interrupted 9 * the current thread. The <i>interrupted status</i> of the 10 * current thread is cleared when this exception is thrown. 11 * @see Object#notify() 12 */ 13 public static native void sleep(long millis) throws InterruptedException;
1 /** 2 * Causes the current thread to wait until another thread invokes the 3 * {@link java.lang.Object#notify()} method or the 4 * {@link java.lang.Object#notifyAll()} method for this object. 5 * In other words, this method behaves exactly as if it simply 6 * performs the call <tt>wait(0)</tt>. 7 * <p> 8 * The current thread must own this object‘s monitor. The thread 9 * releases ownership of this monitor and waits until another thread 10 ... 11 */ 12 public final void wait() throws InterruptedException { 13 wait(0); 14 }
看sleep方法的第4、第5行,"The thread does not lose ownership of any monitors"
看wait方法的第8、第9行,"The thread releases ownership of this monitor"
所以二者的差别就来了,差别就在"monitor"也就是监视器上,sleep和wait方法的执行都会释放CPU资源,但是sleep方法不会释放掉监视器的所有权,而wait方法会释放掉监视器的所有权。所谓监视器,就是假如sleep方法和wait方法处于同步方法/同步方法块中,它们所持有的对象锁
Thread.sleep(0)的作用
讲这个问题,要先讲一下两种线程调度的方法,周志明老师的《深入理解Java虚拟机:JVM高级特性与最佳实践》第12章第4节对这块内容有比较清楚的解释。
线程调度指的是系统为线程分配处理器使用权的过程,主要调度方式有两种:协同式线程调度与抢占式线程调度。
1、协同式线程调度
使用协同式线程调度的多线程系统,线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上。这种调度方式最大的好处就是实现简单,而且由于线程要把自己的事情干完了才会进行线程切换,切换操作对线程自己是可知的,所以没有什么线程同步问题。不过协同式线程调度的坏处也很明显:线程执行时间不受控制。如果一个线程编写有问题,一直不告诉系统进行线程切换,那么程序便会一直阻塞在那儿。所以这种方式非常不稳定,一个线程坚持不让出CPU执行时间就可能会导致整个系统崩溃。
2、抢占式线程调度
抢占式线程调度方式是由系统来分配执行时间的,线程切换不由线程本身来决定。在这种实现线程调度的方式下,线程的执行时间是系统可控的,也不会有一个线程导致整个进程阻塞的问题。
很明显Java采取的是抢占式调度方式。Java的线程是通过映射到系统的原生线程上实现的,在某个线程挂起或者分给它的CPU时间片到了之后,操作系统会根据线程优先级、线程饥饿程度等算出一个总的优先级出来,然后再挑选一个线程,分给它时间片。
讲了这么多,回到我们的主题上,我总结两点:
1、CPU分出来的时间片,可以竞争的线程都是会去竞争获取的
2、调用了Thread.sleep(XXX)方法的线程,意味着在XXX毫秒的时间内,该线程不参与CPU时间片的竞争
那么Thread.sleep(0)是干什么用的呢?它的作用就是:强制操作系统触发一次CPU计算优先级并分配时间片的动作。比如线程A获得了5毫秒的CPU执行时间,如果在执行了2毫秒的时候遇到了Thread.sleep(0)语句,那么后面的3毫秒的时间片就不运行了,操作系统重新计算一次优先级,并分配下一个CPU时间片给哪个线程。
这个小细节对于系统运行是有好处的:
1、避免了某一线程长时间占用CPU资源,我们知道在Java中比如开了两个非守护线程,线程优先级为10的线程A与线程优先级为5的线程B同时执行,这意味着操作系统基本上绝大多数时间都在运行线程A,基本不会把CPU控制权交给线程B
2、避免了系统假死
3、让线程有比较平均的机会获得CPU资源
不过Thread.sleep(0)虽然好,但是不要去滥用它。一个系统CPU占用率高是好事情,这意味着CPU在做事情,没有闲着。但是CPU占用率高还得保证CPU做的事情是应该做的事情,比如CPU占用率高,但是在死循环,有意义吗?这就是代码写得有问题。Thread.sleep(0)也一样,这句语句触发了操作系统计算优先级、分配时间片的动作,势必占用CPU的时间,如果在很多线程里面都滥用这个方法的话,CPU使用率是上去了,但大多数时间做的都是无意义的事情。我认为这个动作的目的更多是为了优化系统,而不是代码必须执行的一部分。
标签:
原文地址:http://www.cnblogs.com/xrq730/p/4927626.html