多线程之Thread 类的基本用法

简介: 多线程之Thread 类的基本用法

大家好,今天为大家带来Thread类的基本方法,咱们接着上期继续讲

目录

🎉 1.线程中断

🎉 2.线程等待

🎉3.线程休眠

🎉4.获取线程实例

🎉5.线程的状态


1.线程中断

上一期说的is Interrupted()就是说线程被中断的事情

线程是否被中断取决于线程 的入口方法是否已经执行完毕

进行线程中断只有一个办法:让线程的入口方法执行完毕(要么return,要么抛异常)

1.给线程设定一个结束标志位

上代码


public class ThreadDemo1 {
    public static boolean isQuit=false;//静态变量
    public static void main(String[] args)  {
        Thread t=new Thread(()->{
            while(!isQuit){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("线程结束");
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //主线程中修改isQuit的值
        isQuit=true;
    }
}

这里为啥一定要把isQuit设置为静态全局变量呢,因为如果放在lambda表达式里,会进行变量捕获,有两个要求,设置的变量必须是final修饰或者是实际final的,啥意思呢


final修饰的就是个常量了


实际final指的是虽然不是个常量,,没有用final修饰,但是没有尝试去修改它的值


而如果这个代码中将isQuit放入lambda表达式中,在主线程中对它又进行了修改,所以会报错.所以最好的方式就是将它作为静态全局变量

dfb64d8837cf4db1bed20b096b984cec.png

如图所示,我们可以看到报红了

上述是一种方式,需要程序员手动设置标志位,那么我们也可以采用Thread类内置的标志位来进行

线程中断

上代码来进行更好的讲解


public class ThreadDemo2 {
    //currentThread是获取当前线程实例的方法
    //isInterrupted是t对象自带的一个标志位
    //interrupt方法就是设置标志位为true
    public static void main(String[] args) {
        Thread t=new Thread(()->{
           while(!Thread.currentThread().isInterrupted()){
               System.out.println("hello   t");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
           }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
           e.printStackTrace();
        }
            t.interrupt();
    }
}


我们先来运行一下这个代码,看看结果

发现了吗,这个线程并没有结束,而是打印了三次,抛出异常,然后继续执行

代码中的e.printStackPrace()打印的是异常调用栈

为啥线程没有按照预期结束呢


首先主线程休眠3000ms,t线程打印三次,这时isInterrupted本身是false,然后主线程苏醒,,调用interrupt方法,将标志位边为true,这时候t线程执行到了sleep那里,那么sleep被提前唤醒,清空了标志位,将true再次变为false,那么这个循环一直为真,也就会一直执行了


那么我们要怎样解决这个问题呢

手动加break


public class ThreadDemo2 {
    //currentThread是获取当前线程实例的方法
    //isInterrupted是t对象自带的一个标志位
    //interrupt方法就是设置标志位为true
    public static void main(String[] args) {
        Thread t=new Thread(()->{
           while(!Thread.currentThread().isInterrupted()){
               System.out.println("hello   t");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                  e.printStackTrace();
                  break;
               }
           }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
           e.printStackTrace();
        }
            t.interrupt();
    }
}

看运行结果

那么为什么sleep要清空标志位呢

让线程对于啥时候结束有一个更精准的控制

使用interrupt不是让线程立即结束,而是告诉线程应该结束了,真正线程结束取决于我们怎样写代码😊


2.线程等待

线程之间是并发执行的,对于线程调度是无序的,我们要想确定线程执行顺序,需要使用线程等待

线程等待这个比较简单,就是使用join,来举个例子


public class ThreadDemo3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            System.out.println("hello t");
        });
        t.start();
        t.join();
        System.out.println("hello main");
    }
}


在主线程中中使用t.join()意思是让主线程阻塞等待,t线程结束以后,再执行主线程


这里有一个误区,让主线程阻塞不是说除了t线程其他所有线程都阻塞了,而是除了主线程阻塞,其他线程照常执行,不受影响


10029b889a8d45f1be736857c7d31c9c.png



这样就保证了线程的执行顺序


如果主线程中调用t.join()时,t正在执行,那么主线程就阻塞等待,直到t线程结束,主线程接着执行


如果主线程调用t.join()时,t已经执行完毕,那么主线程就直接执行即可


3.线程休眠

已经写过很多遍了,就是sleep,就不再赘述了

下一个问题

线程获取实例,

在讲线程中断的时候,也讲过了,currenrtThread()方法就是获取一个线程的实例


线程状态


1.NEW(线程还未创建,就是有个Thread对象)

2.RUNNABLE(正在CPU调度或者即将上CPU调度)

3.TERMINATED(线程已经执行完毕,Thread对象还在)

4.BLOCKED(等待锁出现的状态)

5.TIME_WAITING(指定时间等待.sleep方法)

6.WAITING(使用wait方法出现的状态)

下面通过代码来看一看

public class ThreadDemo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (true) {
                // System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        // 在启动之前, 获取线程状态. NEW
        System.out.println(t.getState());
        t.start();
        //Thread.sleep(2000);
        System.out.println(t.getState());
    }
}


22c8de43983f453fbf12170ba50808ee.png

public class ThreadDemo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (true) {
                // 为了防止 hello会将线程状态覆盖掉 , 先注释这一行
                // System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //  未启动,NEW
        System.out.println(t.getState());
        t.start();
        Thread.sleep(2000);
        System.out.println(t.getState());
    }
}

8d1938374ca14209bb41203d45849fd4.png


总结

线程的状态

NEW

RUNNABLE

TERMINATED

这三个状态是线程的主要状态


然后BLOCKED,TIME_WAITING,WAITING,都是线程执行中可能出现的状态,

简称,一条主线,三个分支,BLOCKED和WAITING后期再讲

今天的讲解就到这里,我们下期再见,886!!!

相关文章
|
4月前
|
Arthas 监控 Java
Arthas thread(查看当前JVM的线程堆栈信息)
Arthas thread(查看当前JVM的线程堆栈信息)
681 10
|
10月前
|
Java C# Python
线程等待(Thread Sleep)
线程等待是多线程编程中的一种同步机制,通过暂停当前线程的执行,让出CPU时间给其他线程。常用于需要程序暂停或等待其他线程完成操作的场景。不同语言中实现方式各异,如Java的`Thread.sleep(1000)`、C#的`Thread.Sleep(1000)`和Python的`time.sleep(1)`。使用时需注意避免死锁,并考虑其对程序响应性的影响。
233 8
|
9月前
|
Java
【JavaEE】——多线程常用类
Callable的call方法,FutureTask类,ReentrantLock可重入锁和对比,Semaphore信号量(PV操作)CountDownLatch锁存器,
|
9月前
|
Java 程序员 调度
【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)
创建线程的五种方式,Thread常见方法(守护进程.setDaemon() ,isAlive),start和run方法的区别,如何提前终止一个线程,标志位,isinterrupted,变量捕获
|
9月前
|
安全 Java API
【JavaEE】多线程编程引入——认识Thread类
Thread类,Thread中的run方法,在编程中怎么调度多线程
|
10月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
179 1
|
2月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
127 0
|
2月前
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
3月前
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
225 5
|
7月前
|
Python
python3多线程中使用线程睡眠
本文详细介绍了Python3多线程编程中使用线程睡眠的基本方法和应用场景。通过 `time.sleep()`函数,可以使线程暂停执行一段指定的时间,从而控制线程的执行节奏。通过实际示例演示了如何在多线程中使用线程睡眠来实现计数器和下载器功能。希望本文能帮助您更好地理解和应用Python多线程编程,提高程序的并发能力和执行效率。
213 20