Java多线程-(5)线程的优先级、sleep()、yield()、join()

时间:2021-10-01 23:32:35

1、线程的优先级


见第3点(yield)中的描述。


2、睡眠

Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)静态方法强制当前正在执行的线程休眠(暂停执行),以“减慢线程”。当线程睡眠时,它入睡在某个地方,在苏醒之前不会返回到可运行状态。当睡眠时间到期,则返回到可运行状态。

线程睡眠的原因:线程执行太快,或者需要强制进入下一轮,因为Java规范不保证合理的轮换。

睡眠的实现:调用静态方法。

    

[java]  view plain copy
  1. try {  
  2.         Thread.sleep(123);  
  3.     } catch (InterruptedException e) {  
  4.         e.printStackTrace();    
  5.     }  


睡眠的位置:为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程中会睡眠。

注意:

1、线程睡眠是帮助所有线程获得运行机会的最好方法。

2、线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。

3、sleep()是静态方法,只能控制当前正在运行的线程。


3、线程的优先级和线程让步yield() 

线程的让步是通过Thread.yield()来实现的。yield()方法的作用是:暂停当前正在执行的线程对象,并执行其他线程


要理解yield(),必须了解线程的优先级的概念。线程总是存在优先级,优先级范围在1~10之间。JVM线程调度程序是基于优先级的抢先调度机制。在大多数情况下,当前运行的线程优先级将大于或等于线程池中任何线程的优先级。但这仅仅是大多数情况。 


注意:当设计多线程应用程序的时候,一定不要依赖于线程的优先级。因为线程调度优先级操作是没有保障的,只能把线程优先级作用作为一种提高程序效率的方法,但是要保证程序不依赖这种操作。 


线程池中线程都具有相同的优先级,调度程序的JVM实现*选择它喜欢的线程。这时候调度程序的操作有两种可能:一是选择一个线程运行,直到它阻塞或者运行完成为止。二是时间分片,为池内的每个线程提供均等的运行机会。 


设置线程的优先级:线程默认的优先级是创建它的执行线程的优先级。可以通过setPriority(int newPriority)更改线程的优先级。

例如:     

[java]  view plain copy
  1. Thread t = new MyThread();  
  2.      t.setPriority(8);  
  3.      t.start();  

线程优先级为1~10之间的正整数,JVM从不会改变一个线程的优先级。然而,1~10之间的值是没有保证的。一些JVM可能不能识别10个不同的值,而将这些优先级进行每两个或多个合并,变成少于10个的优先级,则两个或多个优先级的线程可能被映射为一个优先级。 

线程默认优先级是5Thread类中有三个常量,定义线程优先级范围: 

static int MAX_PRIORITY  线程可以具有的最高优先级。 
static int MIN_PRIORITY   线程可以具有的最低优先级。 
static int NORM_PRIORITY   分配给线程的默认优先级。 


Thread.yield()方法 

Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。 

yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相 同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。 

结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

[java]  view plain copy
  1. /**  
  2. * Java线程:线程的调度-让步  
  3.  
  4. * @author leizhimin 2009-11-4 9:02:40  
  5. */   
  6. public class Test {   
  7.         public static void main(String[] args) {   
  8.                 Thread t1 = new MyThread1();   
  9.                 Thread t2 = new Thread(new MyRunnable());   
  10.   
  11.                 t2.start();   
  12.                 t1.start();   
  13.         }   
  14. }   
  15.   
  16. class MyThread1 extends Thread {   
  17.         public void run() {   
  18.                 for (int i = 0; i < 10; i++) {   
  19.                         System.out.println("线程1第" + i + "次执行!");   
  20.                 }   
  21.         }   
  22. }   
  23.   
  24. class MyRunnable implements Runnable {   
  25.         public void run() {   
  26.                 for (int i = 0; i < 10; i++) {   
  27.                         System.out.println("线程2第" + i + "次执行!");   
  28.                         Thread.yield();   
  29.                 }   
  30.         }   
  31. }  

从下图的输出结果中可以看到yield()方法的作用:

Java多线程-(5)线程的优先级、sleep()、yield()、join()


4join()方法

Thread的非静态方法join()让一个线程B“加入到另外一个线程A的尾部。在A执行完毕之前,B不能工作。例如: 

        Thread t = new MyThread();
        t.start();
        t.join(); 

另外,join()方法还有带超时限制的重载版本。 例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态。 

线程的加入join()线程栈导致的结果是线程栈发生了变化,当然这些变化都是瞬时的。下面给示意图: 

Java多线程-(5)线程的优先级、sleep()、yield()、join()


测试代码:

public class Main {

	public static class TestThread extends Thread {

		@Override
		public void run() {
			int i = 0;
			long time = System.currentTimeMillis();
			while (i <= 10) {
				while (System.currentTimeMillis() - time < 1000) {
				}
				time = System.currentTimeMillis();
				System.out.println(i);
				i++;
			}
		}
	}

	public static void main(String[] args) throws Exception {
		System.out.println("start");
		TestThread testThread = new TestThread();
		testThread.start();
		testThread.join();
		System.out.println("end");
	}
}

输出结果:

Java多线程-(5)线程的优先级、sleep()、yield()、join()




小结 

到目前位置,介绍了线程离开运行状态的3种方法: 

1、调用Thread.sleep():使当前线程睡眠至少多少毫秒(尽管它可能在指定的时间之前被中断)。 

2、调用Thread.yield():不能保障太多事情,尽管通常它会让当前运行线程回到可运行性状态,使得有相同优先级的线程有机会执行。 

3、调用join()方法:保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。


除了以上三种方式外,还有下面几种特殊情况可能使线程离开运行状态: 

1线程run()方法完成。 

2、在对象上调用wait()方法(不是在线程上调用)。 

3线程不能在对象上获得锁定,它正试图运行该对象的方法代码。 

4线程调度程序可以决定将当前运行状态移动到可运行状态,以便让另一个线程获得运行机会,而不需要任何理由。


相关引用:

http://wenku.baidu.com/view/07ccd32f647d27284b735148.html

http://blog.csdn.net/liu1028701143/article/details/6754590

http://blog.csdn.net/jimjarry/article/details/6754598

http://lavasoft.blog.51cto.com/62575/27069