多线程初阶——线程状态

简介: 多线程初阶——线程状态

多线程初阶——线程状态

文章目录

1.Thread类及常见构造方法

image.png


给线程起名字

public class demo1 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while(true){
                System.out.println("Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"线程一");
        t.start();
        while (true){
            System.out.println("main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

a414efd8416481bf5e33ee0ce857cdb7.png

2.Thread常见的方法

属性 方法
ID getId()
名称 getName()
状态 getState()
优先级 getPriority()
是否后台线程 isDaemon()
是否存活 isAlive()
是否被中断 isInterrupted()

说明

getId()

ID是线程唯一标识,不同线程不会重复

getName()

线程的名称

getState()

表示线程当前所处的一个情况

getPriority()

获得线程的优先级

isDaemon()

JVM会在一个进程的所有非后台线程结束后,才会结束运行,这里的后台,和我们常说的手机后台应用类似线程创建的时候,默认是一个前台线程,前台线程可以阻止进程的退出,后台线程不影响进程的退出

public class Demo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println("thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
    }
}

2b306417a141c15b6c9e0c78fdc510e2.png

由于线程是前台进程,需要等待运行结束,进程才结束。代码为死循环,所以将会一直执行。

利用setDaemom()方法将线程设置为后台进程,等主线程执行完,进程就结束了,注意:先设置后台进程,再启动线程

public class Demo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println("thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.setDaemon(true);
        thread.start();
        System.out.println("main.....");
    }
}

3fba8a9361873527d8183f992b755cf4.png

3.线程相关的重要操作

3.1启动线程—start()

创建Thread对象、重写run方法,只是给线程安排了任务,并没有执行,而调用start方法,才是创建出了线程

3.2中断线程

**线程结束其实就是让线程的入口方法执行完 **

而中断线程,其实就是让线程停止下来,结束入口方法的执行

有2种方法可以中断线程

**方法一:直接用自定义的变量来作为标志位 **

需要给标志位上加volatile关键字

这里我们以李四在银行取钱为例

public class Demo8 {
    private static class MyRunnable implements Runnable {
        public volatile boolean isQuit = false;
        @Override
        public void run() {
            while (!isQuit) {
                System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(5 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        target.isQuit = true;
    }
}

a071c9b9a09e1940d644a65fc3c5e246.png

方法二:使用Thread自带的标志位

Thread.interrupted()或者Thread.currenThread().isInterrupted()

public class Demo9 {
 private static class MyRunnable implements Runnable {
     @Override
     public void run() {
         while (!Thread.currentThread().isInterrupted()) {
             System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(5 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        thread.interrupt();
    }
}

运行结果

9c2bc5f5a9d4c9689b64e93fce208b8b.png这时抛出了InterruptedException异常

这是为什么呢?


由于线程的有效任务是打印一句话,这个操作耗时比较小,大部分时间线程都在sleep状态,正常来说,当线程在运行真正有效任务时去中断才是一个有效的中断,而在线程休眠的时候中断,其实是把休眠给中断了,而休眠本身没有到指定的时间,所以抛出了InterruptedException异常


当我们去掉线程中的休眠时,结果如下

524386ebe691ec4e5ce4311456e1bae1.png

这时候线程才真正的中断了

3.3 等待线程— join()

我们知道线程之间的执行顺序是根据系统调度随机执行的,但有时我们需要等待一个线程执行完,再执行下一个线程,这时我们需要一个方法明确等待线程结束

public class Demo10 {
    public static void main(String[] args) throws InterruptedException {
        Runnable target = () -> {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName() + ":正在工作!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "结束了工作");
        };
        Thread thread1 = new Thread(target, "李四");
        Thread thread2 = new Thread(target, "王五");
        System.out.println("李四先工作");
        thread1.start();
        thread1.join();
        System.out.println("李四结束了工作,王五开始工作");
        thread2.start();
        thread2.join();
        System.out.println("王五结束了工作");
    }
}

387fba66e4d6413304414c04f9636f49.png

join()其他方法

public void join() 等待线程结束(一直等,知道线程执行的任务结束)
public void join(long millis) 等待线程结束,但等待millis毫秒
public void join(long millis, int nanos) 同理

3.4 获取线程引用

private static Thread currentThread()

返回当前线程对象的引用

3.5休眠线程—sleep()

让线程休眠休眠一会

图解sleep()的具体使用

2919c2375c91c81c37003b442d77d38f.png

4.线程的状态

在Java线程分为6种状态

1. NEW:创建好了一个Java的Thread对象,并安排好了任务,没有调用start()方法之前,和PCB没有关系

2. RUNNABLE:运行+就绪状态,在执行任务时的一个常态之一

3. TIMED_WAITING:指定了一个时间的阻塞队列,过时不候

4. WAITING :没有指定时间的等待,一直死等

5. BLOCK:等待锁的状态

6. TERMINATED :结束,完成状态,PCB已经被销毁了,但是Java对象还在

查看线程状态

public class Demo14 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("线程创建之前:"+thread.getState());
        thread.start();
        Thread.sleep(1000);
        System.out.println("启动线程,创建好PCB后:"+thread.getState());
        thread.join();
        System.out.println("线程执行完成后:"+thread.getState());
    }
}

b10cf48f71e39b50a194b5f9712cc4bb.png

线程之间相互转换


e4d8d831cf4337f9715cf7fede5ce216.png


目录
相关文章
|
5天前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
17 1
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
60 1
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
33 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
25 2
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
41 2
|
2月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
47 1
|
2月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
54 1
|
2月前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
43 1
|
1月前
|
数据采集 Java Python
爬取小说资源的Python实践:从单线程到多线程的效率飞跃
本文介绍了一种使用Python从笔趣阁网站爬取小说内容的方法,并通过引入多线程技术大幅提高了下载效率。文章首先概述了环境准备,包括所需安装的库,然后详细描述了爬虫程序的设计与实现过程,包括发送HTTP请求、解析HTML文档、提取章节链接及多线程下载等步骤。最后,强调了性能优化的重要性,并提醒读者遵守相关法律法规。
67 0
|
2月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
88 6