多线程之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!!!

目录
打赏
0
0
0
0
0
分享
相关文章
Arthas thread(查看当前JVM的线程堆栈信息)
Arthas thread(查看当前JVM的线程堆栈信息)
151 10
线程等待(Thread Sleep)
线程等待是多线程编程中的一种同步机制,通过暂停当前线程的执行,让出CPU时间给其他线程。常用于需要程序暂停或等待其他线程完成操作的场景。不同语言中实现方式各异,如Java的`Thread.sleep(1000)`、C#的`Thread.Sleep(1000)`和Python的`time.sleep(1)`。使用时需注意避免死锁,并考虑其对程序响应性的影响。
177 8
|
7月前
|
【JavaEE】——多线程常用类
Callable的call方法,FutureTask类,ReentrantLock可重入锁和对比,Semaphore信号量(PV操作)CountDownLatch锁存器,
【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)
创建线程的五种方式,Thread常见方法(守护进程.setDaemon() ,isAlive),start和run方法的区别,如何提前终止一个线程,标志位,isinterrupted,变量捕获
【JavaEE】多线程编程引入——认识Thread类
Thread类,Thread中的run方法,在编程中怎么调度多线程
|
8月前
|
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
155 1
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
88 0
|
5月前
|
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
98 26
|
5月前
|
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
101 17
|
7月前
|
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
534 2
登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问