首页 > 其他分享 >Thread 类使用及常用操作

Thread 类使用及常用操作

时间:2024-04-02 19:02:57浏览次数:39  
标签:常用 Thread System 线程 println 操作 public out

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。

每个执行流,也需要有一个对象来描述,类似下图所示,而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

1 Thread 的常见构造方法

方法

说明

Thread()

创建线程对象

Thread(Runnable target)

使用 Runnable 对象创建线程对象

Thread(String name)

创建线程对象,并命名

Thread(Runnable target, String name)

使用 Runnable 对象创建线程对象,并命名

【了解】Thread(ThreadGroup group, Runnable target)

线程可以被用来分组管理,分好的组即为线程组,这个目前我们了解即可

Thread t1 = new Thread();

Thread t2 = new Thread(new MyRunnable()); Thread t3 = new Thread("这是我的名字");

Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

2 Thread 的几个常见属性

属性

获取方法

ID

getId()

名称

getName()

状态

getState()

优先级

getPriority()

是否后台线程

isDaemon()

是否存活

isAlive()

是否被中断

isInterrupted()

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

名称是各种调试工具用到

状态表示线程当前所处的一个情况,下面我们会进一步说明

优先级高的线程理论上来说更容易被调度到

关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。

是否存活,即简单的理解,为 run 方法是否运行结束了

线程的中断问题,下面我们进一步说明

public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ": 我还
活着");
                    Thread.sleep(1 * 1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
           }
            System.out.println(Thread.currentThread().getName() + ": 我即将死去");
       });
        System.out.println(Thread.currentThread().getName() 
                           + ": ID: " + thread.getId());
        System.out.println(Thread.currentThread().getName() 
                           + ": 名称: " + thread.getName());
        System.out.println(Thread.currentThread().getName() 
                           + ": 状态: " + thread.getState());
        System.out.println(Thread.currentThread().getName() 
                           + ": 优先级: " + thread.getPriority());
        System.out.println(Thread.currentThread().getName() 
                           + ": 后台线程: " + thread.isDaemon());
        System.out.println(Thread.currentThread().getName() 
                           + ": 活着: " + thread.isAlive());
        System.out.println(Thread.currentThread().getName() 
                           + ": 被中断: " + thread.isInterrupted());
        thread.start();
        while (thread.isAlive()) {}
        System.out.println(Thread.currentThread().getName() 
                           + ": 状态: " + thread.getState());
   }
}

3 启动一个线程-start()

之前我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。

覆写 run 方法是提供给线程要做的事情的指令清单线程对象可以认为是把李四、王五叫过来了。而调用 start() 方法,就是喊一声:”行动起来!“,线程才真正独立去执行了。

调用 start 方法, 才真的在操作系统的底层创建出一个线程.

4 中断一个线程

李四一旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加一些机制,例如老板突然来电话了,说转账的对方是个骗子,需要赶紧停止转账,那张三该如何通知李四停止呢?这就涉及到我们的停止线程的方式了。

目前常见的有以下两种方式:

1. 自己定义标志位来控制线程停止

public class ThreadDemo8 {
    private static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (flag) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();

        Thread.sleep(3000);
        // 在主线程里就可以随时通过 flag 变量的取值, 来操作 t 线程是否结束.
        flag = false;
    }
}

2. 使用 Thread 自带的标志位来进行判定

public class ThreadDemo9 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    break;
                }
            }
        });
        t.start();
        Thread.sleep(3000);

        t.interrupt();
    }
}

清除标志位可以把选择权交给程序猿自己,选终止还是继续执行

5 等待一个线程 - join()

        有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。例如,张三只有等李四转账成功,才决定是否存钱,这时我们需要一个方法明确等待线程的结束。主线程main需要等 t 线程执行完才会继续执行

public class ThreadDemo10 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("join 之前");

        // 此处的 join 就是让当前的 main 线程来等待 t 线程执行结束 (等待 t 的 run 执行完)
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join 之后");
    }
}

        如果执行 join 的时候,t 已经结束了。这是 join 不会阻塞,就会立即返回。即线程没结束,等待;线程结束了,立即返回。

方法

说明

public void join()

等待线程结束(一直等)

public void join(long millis)

等待线程结束,最多等 millis 毫秒

public void join(long millis, int nanos)

同理,但可以更高精度

6 获取当前线程引用

这个方法我们非常熟悉了

方法

说明

public static Thread currentThread();

返回当前线程对象的引用

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // currentTimeMillis 获取当前的时间戳
        System.out.println(System.currentTimeMillis());
        Thread.sleep(3 * 1000);
        System.out.println(System.currentTimeMillis());
    }
}

7 休眠当前线程

        因为线程的调度是不可控的,所以,这个方法只能保证实  际休眠时间是大于等于参数设置的休眠时间的。

方法

说明

public static void sleep(long millis) throws InterruptedException

休眠当前线程 millis 毫秒

public static void sleep(long millis, int nanos) throws InterruptedException

可以更高精度的休眠

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {         
           System.out.println(System.currentTimeMillis());
           Thread.sleep(3 * 1000); System.out.println(System.currentTimeMillis());
    }
}

        线程 A 调用 sleep ,A 就会进入休眠状态,把 A 从就绪状态链表中拎出来放到阻塞链表中。比如调用 sleep(1000),对应的线程 PCB 就要在阻塞队列中待1000ms;但是实际上要考虑调度的开销,是无法唤醒后就立即执行的,实际上的时间间隔大概率要大于1000ms

标签:常用,Thread,System,线程,println,操作,public,out
From: https://blog.csdn.net/weixin_43497876/article/details/137168563

相关文章

  • DML(Data Manipulation Language、数据操作语言),用于添加、删除、更新和查询数据库记
    ****************************************************************************************DML(DataManipulationLanguage、数据操作语言),用于添加、删除、更新和查询数据库记录,并检查数据完整性。主要的语句关键字包括INSERT、DELETE、UPDATE、SELECT等。SELECT......
  • Git常用命令大全:让你轻松驾驭版本控制
    前言Git是一款强大的分布式版本控制系统,广泛应用于软件开发中。无论是个人开发者还是团队协作,掌握Git的常用命令是至关重要的。本文将介绍Git的常用命令,帮助您更好地管理代码版本。初始化一个新的仓库gitinit这个命令将在当前目录下创建一个新的Git仓库。克隆一个仓库......
  • 手写简易操作系统(二十)--实现堆内存管理
    前情提要前面我们实现了0x80中断,并实现了两个中断调用,getpid和write,其中write还由于没有实现文件系统,是个残血版,这一节我们实现堆内存管理。一、arena在计算机科学中,“arena”内存管理通常指的是一种内存分配和管理技术,它通常用于动态内存分配和释放。在这种管理......
  • 26版SPSS操作教程(初级第十四章)
    前言#由于导师最近布置了学习SPSS这款软件的任务,因此想来平台和大家一起交流下学习经验,这期推送内容接上一次第十三章的学习笔记,希望能得到一些指正和帮助~粉丝及官方意见说明#针对官方爸爸的意见说的推送缺乏操作过程的数据案例文件澄清如下:1、操作演示的数据全部由我本人......
  • 26版SPSS操作教程(初级第十五章)
    前言#由于导师最近布置了学习SPSS这款软件的任务,因此想来平台和大家一起交流下学习经验,这期推送内容接上一次第十四章的学习笔记,希望能得到一些指正和帮助~粉丝及官方意见说明#针对官方爸爸的意见说的推送缺乏操作过程的数据案例文件澄清如下:1、操作演示的数据全部由我本人......
  • Lock Linux是一个基于Linux的操作系统,它主要关注于系统安全和隐私保护
    LockLinux是一个基于Linux的操作系统,它主要关注于系统安全和隐私保护。LockLinux采用了SELinux(Security-EnhancedLinux)和AppArmor等安全机制,以确保系统的安全性。此外,它还提供了一些额外的功能,如加密的文件系统、安全的网络连接和强制访问控制等。以下是关于LockLinux......
  • SeaTunnel DB2 Source Connector 使用文档(含详细操作步骤)
    DB2是IBM的一款关系型数据库管理系统,JDBCDB2SourceConnector是一个用于通过JDBC读取外部数据源数据的连接器。ApacheSeaTunnel如何支持JDBCDB2SourceConnector?请参考本文档。支持引擎SparkFlinkSeaTunnelZeta引擎主要特性批处理(batch)精确一次(exactly-once)列投......
  • C++ std常用math函数
    std::atan和std::atan2std::atan(x)  即tan(angle)=x  所求angle范围[-PI/2,PI/2] [-90°,90°]std::atan2(y,x)即tan(angle)=y/x 所求angle范围[-PI,PI][-180°,180°]  std::fmod(x,y)计算x/y的浮点余数,如std::fmod(3.1,2)=1.1对浮点数进行......
  • 大模型智能体操作系统(AIOS: LLM Agent Operating System)
    简介:基于大型语言模型(LLM)的智能体的集成和部署充满了挑战,这些挑战损害了它们的效率和功效。这些问题包括LLM上智能体请求的次优调度和资源分配,在智能体和LLM之间的交互过程中维护上下文的困难,以及集成具有不同能力和专业化的异构智能体所固有的复杂性。智能体的数量和复杂性......
  • 让你的文档从静态展示到一键部署可操作验证
    作者:慕扉用户在根据文档进行操作时,会出现根据文档内容搭建环境困难、代码调试失败、功能无法使用的情况,主要是由于文档中有年久失修、没人维护、无法跑通的代码,给用户快速上手带来很多的挑战。为了解决文档中的这些用户体验问题,通过函数计算的能力让阿里云的文档从静态展示升级......