3.1 线程五大状态
其实 还有一个状态,是我们 人为 的!就是 等待状态!它是 在 .start() 执行前,执行的一段延迟代码,这个状态 不属于 我们线程状态的 体系! 但是 确实 是 让 线程的执行 提前进入了一段的等待!
等待状态 不属于 线程五大状态的体系!与 阻塞状态 完全是两个概念!
- 简要概述 这几个状态的关系
- 创建状态:new 一个 Thread 对象的时候,线程就被创建出来了!
- 等待状态:不属于 线程五大状态的体系!而是 人为的 在线程开启之前设定的 延迟等待。
- 就绪状态:调用 start() 后,系统不会立即开启线程!而是通过 CPU 的调度器 让其 进行 随机的 开启(当然 不是真正意义上的随机,CPU 是根据 自身的最优策略选择的!)。
- 运行状态:调度之后,线程 会 获取到 CPU 的资源,即线程的本体!然后 来到 运行状态 执行 我们 添加的事务(任务)。
- 阻塞状态:当调用 seep、wait 或 同步锁 时,线程进入阻塞状态。就是代码不往下继续执行了!阻塞事件解除之后,会重新进入 就绪状态,等待 CPU 的调度!
- 死亡状态:线程中断 或 结束,一旦进入死亡状态,就不能再次启动!
- 线程常用的方法
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止,插队 |
static void yield() | 暂停当前正在执行的线程对象,并执行其它线程 |
void interrupt() | 中断线程,别用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
3.1.1 线程停止
- 不推荐使用 JDK 提供的 stop()、destroy()方法。【已被废弃】
- 推荐线程自己停止下来!
- 建议 使用 一个 标志位进行终止变量。 当 flag == false,则终止线程运行。
package www.muquanyu.lesson03;//测试停止 stop
//1.建议线程正常停止 ---> 利用次数,不建议写死循环!
//2.建议使用标志位 ---> 设置一个标志位
//3.不要使用stop或者destroy等过时或者JDK不建议使用的方法public class StopDemo implements Runnable {
//1.设置一个标识位boolean flag = true;@Overridepublic void run() {
int i = 0;while(flag){
System.out.println("run...Thread-->"+i++);}}public void stop(){
this.flag = false;}public static void main(String[] args) {
StopDemo stopDemo = new StopDemo();new Thread(stopDemo).start();//主线程代码for(int i = 0;i<1000;++i){
System.out.println("run...主线程-->"+i);if(i==900){
//调用stop 方法切换标志位,让线程停止stopDemo.stop();System.out.println("线程该停止了!");}}}
}
有人肯定会说,这不是 仅仅 让 人家不输出了吗?哪里停止了?咋就停止了呢?
这就是 你对 线程五大状态不够理解而导致的。我们知道 线程 一旦被开启,最终都会 自己 走向 死亡状态。 而 这个死亡状态 是在 运行状态 之后 进入的!那么运行状态 在做什么呢?就是在 执行 代码!!!换句话说,事务的代码执行完毕后,线程就会自己 进入 死亡状态! 不需要我们 强制性的关闭。这也是 为什么 不采取 Java 提供的 stop()方法 和 destroy() 方法。
但是你会发现,我们的结果上,好像 看似 多出了 一个子线程的输出!
这是因为什么呢?实际上 没多!
答:
解释①:这是因为 子线程 和 主线程 本来就是互不干扰的,在主线程标识符 刚 更改完毕的同时,子线程 就又输出了一条。然后子线程才发现 自己不该 输出了。所以 才导致,好像 是 多输出了一条现象!
解释②:这是因为 我们的 线程,并不是真正的线程,而是时间快频率的切换,让我们 感觉 好像是 多线程!所以 这里的 Thread 432 确实是 多输出的。
3.1.2 线程休眠
- sleep(时间)指定当前线程阻塞的毫秒数
- sleep 存在异常 InrerruptedException
- sleep 时间达到后,才会让线程进入就绪状态。
- sleep 可以模拟网络延时,倒计时等。而且比 时钟好用多了。它可以用在各个代码段中间,直接调用 sleep 进行代码段的延迟。这么简便的代码。时钟是 完全不能办到的!!!
原理:这是因为 所有的代码,要执行的话,必须 在 线程里面执行!所以 无论是哪个代码段部分,你直接写一个 Thread.sleep(1000);//就把 线程给休眠了,也就达到了 延迟的效果!
- 每一个对象都有一个锁,sleep 是根本不会释放锁的!!!
格式:Thread.sleep(毫秒数);// 直接休眠 该代码 处于的当前线程。该代码运行在 哪个 线程里,就会休眠哪个线程!(这个方式 用的比较多,因为非常的方便!)
格式:Thread t = new Thread(Task); t.sleep(毫秒数); //即使 你这样子 去用,延迟的还是 当前代码段的 线程,而不是 这个 对象!一定要记住,sleep()方法 是Thread中的 静态方法,所以只属于这个类,不属于某个对象。
package www.muquanyu.lesson03;import com.sun.deploy.util.SystemUtils;import java.sql.Date;
import java.text.SimpleDateFormat;public class SleepDemo {
public static void main(String[] args) throws InterruptedException {
for(int i =0;i<10;++i){
Thread.sleep(1000);System.out.println(i);}Date date = new Date(System.currentTimeMillis());SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");while(true){
System.out.println(df.format(date));Thread.sleep(1000);}}
}
取系统时间:Date date = new Date(System.currentTimeMillis())它的参数是一个毫秒数,如果是 正值,就是举例 1970-01-01 那里 距今的 毫秒数是多少。我们直接 取 当前系统时间的毫秒数就完事了。
然后 SimpleDateFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”); 是设置 日期显示格式的。
最后再 通过 format(date) 来显示 日期。然后你会发现 有一个 Thread.sleep(1000) 这样的东西。它就是 循环一次 延迟 一秒的意思!