文档章节

Java并发编程初级篇(三):线程状态以及状态转换过程

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/22 12:11
字数 1338
阅读 76
收藏 2

线程状态:

  • NEW:当一个线程被创建之初,那么此时线程就是新生状态,此状态下线程已经分配完毕内存空间。
  • RUNNABLE:当调用Thread.start()方法后,线程进入就绪状态,此时线程并不会马上开始执行。需要等待JVM选中并分配CPU时间才能开始执行。
  • RUNNING:线程被分配CPU时间后,进入执行状态,在此状态下会运行run()方法中定义的代码。
  • BLOCKED:当处于运行状态的线程,调用一个被阻塞的方法;试图获取一个正在被其他线程占用的锁,都会进入阻塞状态。
  • WAITING:等待状态。当调用了Object.wait()Thread.join()LockSupport.park();方法后线程会进入等待状态。调用Object.wait()的线程会等待Object.notify()方法的调用而重新进入就绪状态。调用Thread.join()方法的线程会等待调用方法线程执行结束而进入结束状态。
  • TIMED_WAITING:固定时间等待状态。此状态下的线程都有一个固定的等待时间,通过调用Object.wait(Long)Thread.sleep(Long)Thread.join(Long),都会让线程进入此状态。处于此状态的线程会等待指定的时间,然后恢复执行。
  • TERMINATED:线程执行结束。

状态转换图:

线程状态转换函数:

  • new Thread():线程创建之初,线程状态为初始状态NEW。
  • Thread.start():线程状态为RUNNABLE,等待JVM分配CUP时间来执行。
  • Thread.sleep(long):线程进入TIMED_WAITING状态,不释放线程持有的锁,会释放计算资源,并等待指定时间后恢复。
  • Object.wait()/Objectwait(long):前者线程进入WAITING状态,并等待被唤醒;后者线程进入TIMED_WAITING,等待指定时间后恢复。但是wait()方法与sleep()方法不同,它会释放线程持有的锁。
  • Thread.join()/Thread.join(long):前者线程进入WAITING状态,并等待加入的线程执行完毕后恢复;后者线程进入TIMED_WAITING,等待指定时间后恢复。
  • synchronized:等待获取锁会使线程进入BLOCKED状态,并一直竞争这个锁,知道获取锁后进入同步块方法,并恢复RUNNABLE状态。

状态转换示例:

定义一个WaitRunnable线程对象,在run()方法中加锁并调用wait()方法模拟等待资源。

public class WaitRunnable implements Runnable{
    @Override
    public void run() {
        System.out.printf("%s:开始执行,准备锁定object。\n", Thread.currentThread().getName());
        synchronized (Main.object) {
            try {
                System.out.printf("%s:成功锁定object,执行同步模块。\n", Thread.currentThread().getName());
                Thread.sleep(3000);
                System.out.printf("%s:被挂起,等待其他线程唤醒自己。\n", Thread.currentThread().getName());
                Main.object.wait();
                System.out.printf("%s: 被唤起,继续开始执行。\n", Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.printf("%s: 执行结束。", Thread.currentThread().getName());
    }
}

定义一个NotifyRunnable线程对象,在run()方法中加锁,并调用notify()方法来唤醒WaitRunnable线程。

package oschian.section_03;

/**
 * Created by hadoop on 2016/11/22.
 */
public class NotifyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.printf("%s:开始执行,准备锁定object。\n", Thread.currentThread().getName());
        synchronized (Main.object) {
            System.out.printf("%s:成功锁定object,执行同步模块。\n", Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.printf("%s: 唤醒其他线程。\n", Thread.currentThread().getName());
            Main.object.notify();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.printf("%s: 执行结束。\n", Thread.currentThread().getName());
    }
}

定义主方法类,启动两个线程,并打印线程状态。

public class Main {
    public static final Object object = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new WaitRunnable());
        Thread thread2 = new Thread(new NotifyRunnable());

        System.out.printf("Main: %s:%s , %s:%s\n", thread1.getName(), thread1.getState(), thread2.getName(), thread2.getState());

        thread1.start();
        thread2.start();

        while (thread1.getState() != Thread.State.TERMINATED
                || thread2.getState() != Thread.State.TERMINATED) {
            System.out.printf("Main: %s:%s , %s:%s\n", thread1.getName(), thread1.getState(), thread2.getName(), thread2.getState());
            Thread.sleep(1000);
        }
    }
}

查看控制台日志:

Main: Thread-0:NEW , Thread-1:NEW
Thread-0:开始执行,准备锁定object。
Thread-0:成功锁定object,执行同步模块。
Main: Thread-0:TIMED_WAITING , Thread-1:RUNNABLE
Thread-1:开始执行,准备锁定object。
Main: Thread-0:TIMED_WAITING , Thread-1:BLOCKED
Main: Thread-0:TIMED_WAITING , Thread-1:BLOCKED
Thread-0:被挂起,等待其他线程唤醒自己。
Thread-1:成功锁定object,执行同步模块。
Main: Thread-0:WAITING , Thread-1:TIMED_WAITING
Main: Thread-0:WAITING , Thread-1:TIMED_WAITING
Main: Thread-0:WAITING , Thread-1:TIMED_WAITING
Thread-1: 唤醒其他线程。Main: Thread-0:BLOCKED , Thread-1:TIMED_WAITING
Main: Thread-0:BLOCKED , Thread-1:TIMED_WAITING
Main: Thread-0:BLOCKED , Thread-1:TIMED_WAITING
Thread-1: 执行结束。Thread-0: 被唤起,继续开始执行。Thread-0: 执行结束。

执行过程分析:

1. Thread-0与Thread-1创建之初。

  • Thread-0:NEW
  • Thread-1:NEW

2. Thread-0先启动,获取锁后进入同步方法快并调用sleep方法等待3秒。Thread-1接着启动,也尝试获取锁,但是锁已经被Thread-0获取,Thread-1等待锁释放。

  • Thread-0:NEW->RUNNABLE->TIMED_WAITNG
  • Thread-1:NEW->RUNNABLE->BLOCKED

3. Thread-0等待3秒后继续执行然后调用wait方法挂起,并释放锁。Thread-1获取到锁后开始执行同步快并等待三秒。

  • Thread-0:TIME_WAITING->RUNNABLE->WAITING
  • Thread-1:BLOCKED->RUNNABLE->TIMED_WAITING

4. Thread-1休眠3秒后唤醒Thread-0,但这个时候锁依然被Thread-1所拥有,然后Thread-1继续休眠3秒。Thread-0等待Thread-1释放锁。

  • Thread-0:WAITING->BLOCKED
  • Thread-1:TIMED_WAITING->RUNNABLE->TIMED_WAITING

5. Thread-1休眠结束后恢复,并执行完毕同步方法快后结束。Thread-0获取锁后恢复,执行完同步方法快后结束。

  • Thread-0:BLOCKED->RUNNABLE->TERMINATED
  • Thread-1:TIMED_WAITING->RUNNABLE->TERNINATED

 

© 著作权归作者所有

共有 人打赏支持
阿拉德大陆的魔法师
粉丝 25
博文 91
码字总数 83019
作品 0
西城
程序员
私信 提问
读书笔记之《Java并发编程的艺术》-并发编程基础

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
8
18《Java核心技术》之一个线程两次调用start()方法会出现什么情况?

一、提出问题 今天我们来深入聊聊线程,相信大家对于线程这个概念都不陌生,它是 Java 并发的基础元素,理解、操纵、诊断线程是 Java 工程师的必修课,但是你真的掌握线程了吗? 今天我们要一...

飞鱼说编程
11/15
0
0
读书笔记之《Java并发编程的艺术》-java中的锁

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
0
读书笔记之《Java并发编程的艺术》-并发编程容器和框架(重要)

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
1
【死磕Java并发】-----J.U.C之AQS:CLH同步队列

此篇博客所有源码均来自JDK 1.8 在上篇博客【死磕Java并发】-----J.U.C之AQS:AQS简介中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列。 CLH同步队列是一个FIFO双向队列,AQS依赖...

chenssy
2017/06/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java框架学习日志-7(静态代理和JDK代理)

静态代理 我们平时去餐厅吃饭,不是直接告诉厨师做什么菜的,而是先告诉服务员点什么菜,然后由服务员传到给厨师,相当于服务员是厨师的代理,我们通过代理让厨师炒菜,这就是代理模式。代理...

白话
今天
15
0
Flink Window

1.Flink窗口 Window Assigner分配器。 窗口可以是时间驱动的(Time Window,例如:每30秒钟),也可以是数据驱动的(Count Window,例如:每一百个元素)。 一种经典的窗口分类可以分成: 翻...

满小茂
今天
9
0
my.ini

1

architect刘源源
今天
10
0
docker dns

There is a opensource application that solves this issue, it's called DNS Proxy Server It's a DNS server that solves containers hostnames, if could not found a hostname that mat......

kut
今天
11
0
寻找数学的广度——《这才是数学》读书笔记2700字

寻找数学的广度——《这才是数学》读书笔记2700字: 文|程哲。数学学习方式之广:国内外数学教育方面的专家,进行了很多种不同的数学学习方式尝试,如数学绘本、数学游戏、数学实验、数学步道...

原创小博客
今天
21
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部