浅墨散人 浅墨散人
  • 基础
  • 设计模式
  • JVM
  • Maven
  • SpringBoot
  • 基础
  • Flask
  • Diango
  • Pandas
  • SqlAlchemy
  • Sqoop
  • Flume
  • Flink
  • Hadoop
  • Hbase
  • Hive
  • Kafka
  • Kylin
  • Zookeeper
  • Tez
  • MySQL
  • Doris
  • Chrome
  • Eclipse
  • IDEA
  • iTerm2
  • Markdown
  • SublimeText
  • VirtualBox
  • WebStrom
  • Linux
  • Mac
  • Hexo
  • Git
  • Vue
  • VuePress
  • 区块链
  • 金融
数据仓库
数据治理
读书笔记
关于我
GitHub (opens new window)
  • 基础
  • 设计模式
  • JVM
  • Maven
  • SpringBoot
  • 基础
  • Flask
  • Diango
  • Pandas
  • SqlAlchemy
  • Sqoop
  • Flume
  • Flink
  • Hadoop
  • Hbase
  • Hive
  • Kafka
  • Kylin
  • Zookeeper
  • Tez
  • MySQL
  • Doris
  • Chrome
  • Eclipse
  • IDEA
  • iTerm2
  • Markdown
  • SublimeText
  • VirtualBox
  • WebStrom
  • Linux
  • Mac
  • Hexo
  • Git
  • Vue
  • VuePress
  • 区块链
  • 金融
数据仓库
数据治理
读书笔记
关于我
GitHub (opens new window)
  • Java基础

    • Java基础
    • CSS自定义滚动条样式
    • Java发送短信
    • 线程的优先级
    • 线程的同步之Synchronized在单例模式中的应用
    • 线程的同步之Synchronized的使用
    • 线程的基本概念
    • 线程的死锁
    • 线程的状态和常用操作
      • 1. 线程的状态
        • 1.1 新生状态
        • 1.2 就绪状态
        • 1.3 运行状态
        • 1.4 阻塞状态
        • 1.5 死亡状态
      • 2. 线程的一些常用操作
        • 2.1 线程的合并:join
        • 2.2 线程的暂停:yield
        • 2.3 线程的(睡眠)暂停:sleep 休眠不释放锁【】
        • 2.4 守护线程(线程的后台运行):thread.setDaemon(true);
      • 3. 总结
        • 3.1 造成线程阻塞的方法?
        • 3.2 Java的守护进程(后台进程)?
        • 3.3 造成线程阻塞后,线程回到哪个状态了?
        • 3.4 哪些状态之后是回到就绪状态?
        • 3.5 sleep会释放锁吗?
        • 3.6 线程都有哪些状态?具体是怎么运行的?
  • Java
  • Basic
2016-03-29
目录

线程的状态和常用操作

# 1. 线程的状态

每个 Java 程序都有一个缺省的主线程,对于 Java 应用程序,主线程是 main()方法执行的线索;对于 Applet 程序,主线程是指挥浏览器加载并执行 Java Applet 程序的线索。要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有五种状态,即创建、就绪、运行、阻塞、终止。

# 1.1 新生状态

在程序中用构造方法(new操作符)创建一个新线程时,如new Thread(r),该线程就是创建状态,此时它已经有了相应的内存空间和其它资源,但是还没有开始执行。

# 1.2 就绪状态

新建线程对象后,调用该线程的 start()方法就可以启动线程。当线程启动时,线程进入就绪状态(runnable)。由于还没有分配CPU,线程将进入线程队列排队,等待 CPU 服务,这表明它已经具备了运行条件。当系统挑选一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态。系统挑选的动作称之为“CPU调度"。一旦获得CPU线程就进入运行状态并自动调用自己的run方法。

# 1.3 运行状态

当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run()方法。 run()方法定义了该线程的操作和功能。运行状态中的线程执行自己的run方法中代码。直到调用其他方法或者发生阻塞而终止。

# 1.4 阻塞状态

一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入输出操作时,将让出 CPU 并暂时中止自己的执行,进入堵塞状态。在可执行状态下,如果调用 sleep()、 suspend()、 wait()等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有当引起堵塞的原因被消除后,线程转入就绪状态。重新到就绪队列中排队等待,这时被CPU调度选中后会从原来停止的位置开始继续执行。

记住:阻塞被消除后是回到就绪状态,不是运行状态。

# 1.5 死亡状态

线程调用 stop()方法、destory()方法或 run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。 不推荐使用stop()方法【会产生异常】 destory()方法【destory是强制终止,不会释放锁】 推荐使用boolen标识来停止线程,如下方式:

class TestThraed implements Runnable{
    private boolean flag = true;//线程使用标识
    @Override
    public void run() {
        while (flag) {
            for (int i = 0; i < 10; i++) {
                System.out.println("TestThread在运行"+i);
            }
        }
    }
    //停止线程
    public void stop(){
        //如果是extends Thread方式实现多线程。不能使用stop方法名。因为Thread类中对stop修饰为final不可重写
        this.flag = false;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以通过getState()方法来获取线程当前的状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED 线程的状态经典图: 分析上图: 1、线路1:新生-->就绪(Runnable)-->运行(Running)-->sleep或者join造成阻塞-->回到就绪(Runnable)-->运行(Running)-->死亡 2、线路2:新生-->就绪(Runnable)-->运行(Running)-->遇到synchronized,需要等待锁的释放。释放完成后-->回到就绪(Runnable)-->运行(Running)-->死亡 3、线路3:新生-->就绪(Runnable)-->运行(Running)-->遇到wait造成的等待需要唤醒notify。醒了后-->回到就绪(Runnable)-->运行(Running)-->死亡

# 2. 线程的一些常用操作

//取得线程的名字 Thread t = Thread.currentThread(); String name = t.getName(); //设置线程的名字 SetNameThreadDemo tt = new SetNameThreadDemo();//继承Thread或者实现Runnable接口的线程类 tt.setName("test thread"); //判断线程是否启动 调用start()方法之前t.isAlive() = false 调用start()方法之后t.isAlive() = true

# 2.1 线程的合并:join

线程的合并是指将某一个线程A在调用A.join()方法合并到正在运行的另一个线程B中,此时线程B处于阻塞状态需要等到线程A执行完毕后才开始线程B的继续执行,代码如下:

public class JoinDemo {
    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();
        Thread t1 = new Thread(t);
        t1.start();
        for (int i = 0; i < 100; i++) {
            /**
             * 当main线程中的i等于50的时候,就把t1线程合并到main线程中执行。此时main线程是处于阻塞状态
             * 直到t1线程执行完成后,main才开始继续执行
             */
            if (50==i) {
                t1.join();
            }
            System.out.println("main.."+i);
        }
    }
}
class TestThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("join.."+i);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

join的执行结果如下:

main..0
.....省略.......
main..17
join..0
join..1
.....省略.......
main..49   //当main的i=50的时候就把t1合并到main线程中,直到t1线程执行完成后,才开始执行main线程。
join..5 - join..99
main..50
main..51 - main..99
1
2
3
4
5
6
7
8
9
10

# 2.2 线程的暂停:yield

该暂停方法暂停的时候不一定就暂停了,取决于CPU,假如刚暂停CPU调度又调到了该线程那就又启动了.....

public class YieldDemo {
    public static void main(String[] args) throws InterruptedException {
        TestThread1 t = new TestThread1();
        Thread t1 = new Thread(t);
        t1.start();
        for (int i = 0; i < 100; i++) {
            //当main线程中的i是20的倍数时,就暂停main线程
            if (i%20==0) {
                Thread.yield();//yield写在哪个线程体中,就暂停哪个线程。这里是在main里,就暂停main线程
                System.out.println("main线程暂停");
            }
            System.out.println("main.."+i);
        }
    }
}
class TestThread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("join.."+i);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

yield的执行结果如下:

main线程暂停
main..0
main..19
main线程暂停
main..20
main..39
main线程暂停
main..40
main..59
main线程暂停
main..79
main线程暂停
main..80
main..84
join..0
join..1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2.3 线程的(睡眠)暂停:sleep 休眠不释放锁【抱着锁睡觉】

实例:10秒倒计时,当前线程每睡1秒就打印一个数字

public static void main(String[] args) throws InterruptedException {
    int num = 10;
    while (true) {
        System.out.println(num--);
        Thread.sleep(1000);
        if (num<=0) {
            break;
        }
    }
}
1
2
3
4
5
6
7
8
9
10

# 2.4 守护线程(线程的后台运行):thread.setDaemon(true);

线程的后台运行

  1. 对 Java 程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程在运行,这个进程就会结束。
  2. 如果某个线程对象在启动(调用 start()方法)之前调用了 setDaemon(true)方法,这个线程就变成了后台线程。
public class ThreadDaemon {
    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        Thread thread = new Thread(t);
        thread.setDaemon(true);//设置后台运行
        thread.start();
    }
}
class ThreadTest implements Runnable{
    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName()+" is running");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3. 总结

# 3.1 造成线程阻塞的方法?

阻塞线程的方法:join、yield、sleep 和Object的wait()方法

# 3.2 Java的守护进程(后台进程)?

设置线程为后台进程运行:setDaemon(true) 如果一个进程中只有后台线程在运行,这个进程就会结束。

# 3.3 造成线程阻塞后,线程回到哪个状态了?

通过join、yield、sleep造成线程阻塞后是回到了就绪状态

# 3.4 哪些状态之后是回到就绪状态?

  1. 通过join、yield、sleep造成线程阻塞后是回到了就绪状态
  2. 遇到synchronized后
  3. 遇到Object的等待wait方法后

# 3.5 sleep会释放锁吗?

sleep不会释放锁【它会抱着锁睡觉】

# 3.6 线程都有哪些状态?具体是怎么运行的?

线程有:创建、就绪、运行、阻塞、终止。5种状态

  1. 通过new关键字创建后,进入到新生状态
  2. 调用start后进入就绪状态
  3. CPU调度到本线程后,本线程开始执行。进入到运行状态
  4. 运行中遇到join,yield,sleep造成阻塞,进入阻塞状态。阻塞完成后,又回到就绪状态
  5. 线程正常执行完,或者遇到异常终止后,进入死亡状态
  6. 终止线程有哪几种方法? 线程调用 stop()方法、destory()方法或 run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。 推荐使用boolen标识来停止线程
#java#Thread
最后更新时间: 2022/7/23 10:17:11
线程的死锁

← 线程的死锁

最近更新
01
分区分桶
08-21
02
数据模型(重要)
08-21
03
安装和编译
08-21
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式