由Thread.sleep引发的

来源:互联网 发布:梅阿查实况巅峰数据 编辑:程序博客网 时间:2024/05/17 09:07

首先,对比下sleep和wait的区别

sleep() is a method which is used to hold the process for few seconds or the time you wanted but in case of wait() method thread goes in waiting state and it won’t come back automatically until we call the notify() or notifyAll().

The major difference is that wait() releases the lock or monitor while sleep() doesn’t releases any lock or monitor while waiting. Wait is used for inter-thread communication while sleep is used to introduce pause on execution, generally.

Thread.sleep() sends the current thread into the “Not Runnable” state for some amount of time. The thread keeps the monitors it has acquired — i.e. if the thread is currently in a synchronized block or method no other thread can enter this block or method. If another thread calls t.interrupt() it will wake up the sleeping thread. Note that sleep is a static method, which means that it always affects the current thread (the one that is executing the sleep method). A common mistake is to call t.sleep() where t is a different thread; even then, it is the current thread that will sleep, not the t thread.

object.wait() sends the current thread into the “Not Runnable” state, like sleep(), but with a twist. Wait is called on an object, not a thread; we call this object the “lock object.” Before lock.wait() is called, the current thread must synchronize on the lock object; wait() then releases this lock, and adds the thread to the “wait list” associated with the lock. Later, another thread can synchronize on the same lock object and call lock.notify(). This wakes up the original, waiting thread. Basically, wait()/notify() is like sleep()/interrupt(), only the active thread does not need a direct pointer to the sleeping thread, but only to the shared lock object.

synchronized(LOCK) {       Thread.sleep(1000); // LOCK is held}synchronized(LOCK) {       LOCK.wait(); // LOCK is not held}

Let categorize all above points :

Call on:

  •     wait(): Call on an object; current thread must synchronize on the lock object.
  •     sleep(): Call on a Thread; always currently executing thread.

Synchronized:

  •     wait(): when synchronized multiple threads access same Object one by one.
  •     sleep(): when synchronized multiple threads wait for sleep over of sleeping thread.

Hold lock:

  •     wait(): release the lock for other objects to have chance to execute.
  •     sleep(): keep lock for at least t times if timeout specified or somebody interrupt.

Wake-up condition:

  •     wait(): until call notify(), notifyAll() from object
  •     sleep(): until at least time expire or call interrupt().

Usage:

  •     sleep(): for time-synchronization and;
  •     wait(): for multi-thread-synchronization.

之前一直有误解就是,sleep肯定是占用cpu的,而wait不占用cpu,这就是为什么大家经常推荐wait


后来查到的资料,和自己写程序验证,sleep期间也是不占用cpu的,首先要先了解java线程的状态


新建状态:用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存 
就绪状态:当一个线程创建了以后,其他的线程调用了它的start()方法,该线程就进入了就绪状态。处于这个状态的线程位于可运行池中,等待获得CPU的使用权 
运行状态:处于这个状态的线程占用CPU,执行程序的代码 
阻塞状态:当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到运行状态。 
阻塞状态分为三种情况: 
1、 位于对象等待池中的阻塞状态:当线程运行时,如果执行了某个对象的wait()方法,java虚拟机就回把线程放到这个对象的等待池中 
2、 位于对象锁中的阻塞状态,当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。 
3、 其它的阻塞状态:当前线程执行了sleep()方法,或者调用了其它线程的join()方法,或者发出了I/O请求时,就会进入这个状态中。 

死亡状态:当线程退出了run()方法,就进入了死亡状态,该线程结束了生命周期。 
           或者正常退出 
           或者遇到异常退出 
           Thread类的isAlive()方法判断一个线程是否活着,当线程处于死亡状态或者新建状态时,该方法返回false,在其余的状态下,该方法返回true. 


线程调度 
线程调度模型:分时调度模型和抢占式调度模型 
JVM采用抢占式调度模型。 
所谓的多线程的并发运行,其实是指宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务。 
(线程的调度不是跨平台,它不仅取决于java虚拟机,它还依赖于操作系统) 

如果希望明确地让一个线程给另外一个线程运行的机会,可以采取以下的办法之一 
1、 调整各个线程的优先级 
2、 让处于运行状态的线程调用Thread.sleep()方法 
3、 让处于运行状态的线程调用Thread.yield()方法 
4、 让处于运行状态的线程调用另一个线程的join()方法 

调整各个线程的优先级 
Thread类的setPriority(int)和getPriority()方法分别用来设置优先级和读取优先级。 
如果希望程序能够移值到各个操作系统中,应该确保在设置线程的优先级时,只使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY这3个优先级。 

线程睡眠:当线程在运行中执行了sleep()方法时,它就会放弃CPU,转到阻塞状态。 
线程让步:当线程在运行中执行了Thread类的yield()静态方法时,如果此时具有相同优先级的其它线程处于就绪状态,那么yield()方法将把当前运行的线程放到运行池中并使另一个线程运行。如果没有相同优先级的可运行线程,则yield()方法什么也不做。 
Sleep()方法和yield()方法都是Thread类的静态方法,都会使当前处于运行状态的线程放弃CPU,把运行机会让给别的线程,两者的区别在于: 
         1、sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。 
2、当线程执行了sleep(long millis)方法后,将转到阻塞状态,参数millis指定睡眠时间;当线程执行了yield()方法后,将转到就绪状态。 
          3、sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明抛出任何异常 
          4、sleep()方法比yield()方法具有更好的移植性 

等待其它线程的结束:join() 
          当前运行的线程可以调用另一个线程的 join()方法,当前运行的线程将转到阻塞状态,直到另一个线程运行结束,它才恢复运行。 

定时器Timer:在JDK的java.util包中提供了一个实用类Timer, 它能够定时执行特定的任务。 


下面写个程序查看sleep线程的cpu占用率

public class Main {    public static void main(String[] args) {        new Thread(new Idle(), "Idle").start();        new Thread(new Busy(), "Busy").start();    }} class Idle implements Runnable {     @Override    public void run() {        try {            TimeUnit.HOURS.sleep(1);        } catch (InterruptedException e) {        }    }} class Busy implements Runnable {    @Override    public void run() {        while(true) {            "Foo".matches("F.*");        }    }}

运行程序

top 找到进程的pid = 10149

查看进程下的所有线程(-H是显示线程)

top -H -p 10149

这是会显示十几个线程,其中有两个是我们的工作线程,busy和Idle,剩下的大部分是gc线程

查看jvm中这些线程的详细信息

jstack 10149


看到其中有两条信息

"Busy" prio=10 tid=0x00007f2a700d0800 nid=0x27c7 runnable [0x00007f29f5c68000]

"Idle" prio=10 tid=0x00007f2a700ce800 nid=0x27c6 waiting on condition [0x00007f29f5d69000]


printf "%d" 0x27c7

就可以看到十进制的线程号


通过这个线程号查看 top -H -p 10149中显示的cpu占用率和mem占用率即可


也可以用  printf "%x" 10183 活动线程的十六进制线程号,查看在jstack中的信息。


通过上述操作可以看到Idle的线程cpu的占用率为0




参考:http://howtodoinjava.com/2013/03/08/difference-between-sleep-and-wait/

http://blog.csdn.net/android_tutor/article/details/5293974

原创粉丝点击