Java多线程编程1----基础知识--暂停线程(sleep(),yield(),join()详解)
来源:互联网 发布:iframe 跨域调用js 编辑:程序博客网 时间:2024/06/07 07:21
1.睡眠----sleep();
2.优先级和yield()方法;
3.调用join()方法
4.suspend与resume方法。(不建议使用)
1、睡眠
Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)静态方法强制当前正在执行的线程休眠(暂停执行),以“减慢线程”。当线程睡眠时,它入睡在某个地方,在苏醒之前不会返回到可运行状态。当睡眠时间到期,则返回到可运行状态。睡眠的原因:线程执行太快,或者需要强制进入下一轮,因为Java规范不保证合理的轮换。
睡眠的位置:为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程中会睡眠。
睡眠的实现:调用静态方法。
try {
Thread.sleep(123);
} catch (InterruptedException e) {
e.printStackTrace();
}
源码:
public static native void sleep(long millis) throws InterruptedException;
例如,将一个耗时的操作改为睡眠,以减慢线程的执行。可以这么写:
public void run() { for(int i = 0;i<5;i++){// 很耗时的操作,用来减慢线程的执行// for(long k= 0; k <100000000;k++); try { Thread.sleep(3000); //<span style="color:black;">线程在每次执行过程中,总会睡眠</span><span style="color:black;">3</span><span style="color:black;">毫秒,睡眠了,其他的线程就有机会执行了。</span> } catch (InterruptedException e) { e.printStackTrace(); . } System.out.println(this.getName()+" :"+i); } }注意:
1).线程睡眠是帮助所有线程获得运行机会的最好方法。
2).线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
3).sleep()是静态方法,只能控制当前正在运行的线程。
下面给例子:一个计数器,计数到5,在每个数字之间暂停1秒,每隔2个数字输出一个字符串
public class MyThread3 extends Thread { public void run() { for (int i = 0; i < 5; i++) { if ((i) % 2 == 0) { System.out.println("-------" + i); } System.out.print(i); try { Thread.sleep(1000); System.out.print(" 线程睡眠1秒!\n"); } catch (InterruptedException e) { e.printStackTrace(); } } }}class Test3 { public static void main(String[] args) { MyThread3 thread3 = new MyThread3(); thread3.start(); }}-------0
0 线程睡眠1秒!
1 线程睡眠1秒!
-------2
2 线程睡眠1秒!
3 线程睡眠1秒!
-------4
4 线程睡眠1秒!注意,是每次输出i后,过1秒再输出线程睡眠**秒
2、线程的优先级和线程让步yield()
线程的让步是通过Thread.yield()来实现的。yield()方法的作用是:暂停当前正在执行的线程对象,并执行其他线程。
要理解yield(),必须了解线程的优先级的概念。
2.1、优先级
线程总是存在优先级,优先级范围在1~10之间,优先级较高的线程得到的CPU资源较多,也就是CPU优先执行优先级较高的线程对象中的任务。JVM线程调度程序是基于优先级的抢先调度机制。在大多数情况下,当前运行的线程优先级将大于或等于线程池中任何线程的优先级。但这仅仅是大多数情况。
注意:当设计多线程应用程序的时候,一定不要依赖于线程的优先级。因为线程调度优先级操作是没有保障的,只能把线程优先级作用作为一种提高程序效率的方法,但是要保证程序不依赖这种操作。
当线程池中线程都具有相同的优先级,调度程序的JVM实现自由选择它喜欢的线程。这时候调度程序的操作有两种可能:一是选择一个线程运行,直到它阻塞或者运行完成为止。二是时间分片,为池内的每个线程提供均等的运行机会。
设置线程的优先级:设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优先执行。线程默认的优先级是创建它的执行线程的优先级。可以通过setPriority(int newPriority)更改线程的优先级。例如:
Thread t = new MyThread();
t.setPriority(8);
t.start();
优先级具有规则性:高优先级的线程总是大部分先执行完,但不代表高优先级的线程全部先执行完,因为优先级也具有随机性。另外,当线程优先级的等级差距很大时,谁先执行完和代码的调用顺序无关。也就是说,线程优先级与打印顺序无关,不要将这两者的关系相关联,它们的关系具有不确定性和随机性。
线程优先级为1~10之间的正整数,如果小于1或大于10,则JDK抛出异常throw new IllegalArgumentExceptionno, JVM从不会改变一个线程的优先级。然而,1~10之间的值是没有保证的。一些JVM可能不能识别10个不同的值,而将这些优先级进行每两个或多个合并,变成少于10个的优先级,则两个或多个优先级的线程可能被映射为一个优先级。
线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:
1).static int MAX_PRIORITY 线程可以具有的最高优先级(10)。
2).static int MIN_PRIORITY 线程可以具有的最低优先级(1)。
3).static int NORM_PRIORITY 分配给线程的默认优先级(5)。
2.1.1.优先级的继承性
在Java中,线程的优先性具有继承性,比如线程1启动线程2,则线程2的优先级与线程1是一样的。
public class MyThread1 extends Thread { public void run() { System.out.println("MyThread1 run priority = " + this.getPriority()); new MyThread2().start(); }}
public class MyThread2 extends Thread{ public void run() { System.out.println("MyThread2 run priority = " + this.getPriority()); }}
class Test4 { public static void main(String[] args) { System.out.println("main thread begin priority = " + Thread.currentThread().getPriority()); Thread.currentThread().setPriority(6); System.out.println("main thread end priority = " + Thread.currentThread().getPriority()); MyThread1 thread1 = new MyThread1(); thread1.start(); }}main thread begin priority = 5
main thread end priority = 6
MyThread1 run priority = 6
MyThread2 run priority = 6优先级被更改再继承
-------------------------------------------------------------------------------------------------------
2.2、Thread.yield()方法
Thread.yield()方法作用是:放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。(暂停当前正在执行的线程对象,并执行其他线程。)
yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
在本示例中,可以取得运行的时间,作为比较结果,测试yield方法的使用效果。
public class MyThread extends Thread{ public void run() { long beginTime = System.currentTimeMillis(); int count = 0; for (int i = 0; i<9000000; i++) { Thread.yield(); count = count + (i + 1); } long endTime = System.currentTimeMillis(); System.out.println("用时: " + (endTime - beginTime) + "毫秒"); }}class TestThread { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); myThread.start(); }}用时: 1004毫秒
用时这么长的原因是将CPU让给其他资源导致速度变慢
把Thread.yield()注释掉,用时: 13毫秒!!
2.3、join()方法
Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。例如:
Thread t = new MyThread();
t.start();
t.join();
另外,join()方法还有带超时限制的重载版本。例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态。
线程的加入join()对线程栈导致的结果是线程栈发生了变化,当然这些变化都是瞬时的。
小结
到目前位置,介绍了线程离开运行状态的3种方法:
1).调用Thread.sleep():使当前线程睡眠至少多少毫秒(尽管它可能在指定的时间之前被中断)。
2).调用Thread.yield():不能保障太多事情,尽管通常它会让当前运行线程回到可运行性状态,使得有相同优先级的线程有机会执行。
3).调用join()方法:保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。
除了以上三种方式外,还有下面几种特殊情况可能使线程离开运行状态:
1).线程的run()方法完成。
2).在对象上调用wait()方法(不是在线程上调用)。
3).线程不能在对象上获得锁定,它正试图运行该对象的方法代码。
4).线程调度程序可以决定将当前运行状态移动到可运行状态,以便让另一个线程获得运行机会,而不需要任何理由。
- Java多线程编程1----基础知识--暂停线程(sleep(),yield(),join()详解)
- Java多线程-线程状态、sleep()、yield()、join()
- Java多线程-(5)线程的优先级、sleep()、yield()、join()
- Java线程sleep,yield,join,wait方法详解
- [疯狂Java]多线程:线程控制(join、daemon、sleep、yield、优先级)
- Java多线程笔记三(线程通信wait/notify/notifyAll/sleep/yield/join)
- 线程的wait、sleep、join、yield详解
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join) (r)
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)(转)
- 线程Sleep、Yield、Join
- Java多线程:(三)一些方法:start(),sleep(),yield(),join()
- java 线程 --- join,sleep,yield 基础学习
- 黑马程序员——Java多线程—join、sleep、yield、后台线程、线程优先级
- java 多线程(2) 线程的调度和优先级 / sleep() / interrupt() 打断join() / yield() / setPriority()
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
- How do I keep my driver from running out of kernel-mode stack
- 计算机病毒常识
- spring(基础11) Spring AOP 实现原理
- 监听器
- MongoDB插入文档
- Java多线程编程1----基础知识--暂停线程(sleep(),yield(),join()详解)
- AngularJS快速开始
- 第十一周 阅读程序(1)
- Bootstrap 栅格系统
- 129. Sum Root to Leaf Numbers
- MongoDB更新文档
- 常用图像插值算法分析与比较
- zabbix 添加主机成功失败判断
- 动态规划—Problem L