Thread的基本用法

创建线程

方法一 继承Thread类

继承 Thread 来创建一个线程类.

class MyThread extends Thread {
  @Override
  public void run() {
    System.out.println("这里是线程运行的代码");
 }
}

 创建 MyThread 类的实例

MyThread t = new MyThread();

调用 start 方法启动线程

t.start(); // 线程开始运行

方法2 实现 Runnable 接口

实现 Runnable 接口

class MyRunnable implements Runnable {
  @Override
  public void run() {
    System.out.println("这里是线程运行的代码");
 }
}

创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数.

Thread t = new Thread(new MyRunnable());

 调用 start 方法

t.start(); // 线程开始运行

对比上面两种方法:

  • 继承 Thread 类, 直接使用 this 就表示当前线程对象的引用
  • 实现 Runnable 接口, this 表示的是 MyRunnable 的引用. 需要使用 Thread.currentThread()

其他变形

匿名内部类创建 Thread 子类对象

// 使用匿名类创建 Thread 子类对象
Thread t1 = new Thread() {
  @Override
  public void run() {
    System.out.println("使用匿名类创建 Thread 子类对象");
 }
};

匿名内部类创建 Runnable 子类对象

// 使用匿名类创建 Runnable 子类对象
Thread t2 = new Thread(new Runnable() {
  @Override
  public void run() {
    System.out.println("使用匿名类创建 Runnable 子类对象");
 }
});

lambda 表达式创建 Runnable 子类对象

// 使用 lambda 表达式创建 Runnable 子类对象
Thread t3 = new Thread(() -> System.out.println("使用匿名类创建 Thread 子类对象"));
Thread t4 = new Thread(() -> {
  System.out.println("使用匿名类创建 Thread 子类对象");
});

多线程的优势

可以观察多线程在一些场合下是可以提高程序的整体运行效率的。

  • 使用 System.nanoTime() 可以记录当前系统的 纳秒 级时间戳.
  • serial 串行的完成一系列运算. concurrency 使用两个线程并行的完成同样的运算.
public class ThreadAdvantage {
  // 多线程并不一定就能提高速度,可以观察,count 不同,实际的运行效果也是不同的
  private static final long count = 10_0000_0000;
  public static void main(String[] args) throws InterruptedException {
    // 使用并发方式
    concurrency();
    // 使用串行方式
    serial();
 }
  private static void concurrency() throws InterruptedException {
    long begin = System.nanoTime();
   
    // 利用一个线程计算 a 的值
    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        int a = 0;
        for (long i = 0; i < count; i++) {
          a--;
       }
     }
   });
    thread.start();
    // 主线程内计算 b 的值
    int b = 0;
    for (long i = 0; i < count; i++) {
      b--;
   }
    // 等待 thread 线程运行结束
    thread.join();
   
    // 统计耗时
    long end = System.nanoTime();
    double ms = (end - begin) * 1.0 / 1000 / 1000;
    System.out.printf("并发: %f 毫秒%n", ms);
 }
  private static void serial() {
    // 全部在主线程内计算 a、b 的值
    long begin = System.nanoTime();
    int a = 0;
    for (long i = 0; i < count; i++) {
      a--;
   }
    int b = 0;
    for (long i = 0; i < count; i++) {

      b--;
   }
    long end = System.nanoTime();
    double ms = (end - begin) * 1.0 / 1000 / 1000;
    System.out.printf("串行: %f 毫秒%n", ms);
 }
}

运行结果:

并发: 399.651856 毫秒
串行: 720.616911 毫秒

Thread 类及常见方法

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。用我们上面的例子来看,每个执行流,也需要有一个对象来描述,类似下图所示,而Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

970bbcff86694625be75841d9e2ba95e.png

Thread 的常见构造方法

1cf08ac4337c4cc9aec1d5ba6cb6558d.png

Thread 的几个常见属性

8177c1ceda214d478c0bff4f175fd80a.png

启动一个线程-start()

之前我们已经看到了如何通过重写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。run方法只是告诉描述了多线程要去执行的任务内容。

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

中断一个线程

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

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

  1. 通过共享的标记来进行沟通
  2. 调用 interrupt() 方法来通知

示例1:使用自定义的变量来作为标志位.

public class ThreadDemo {
  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(10 * 1000);
    System.out.println(Thread.currentThread().getName()
        + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
    target.isQuit = true;
 }
}

示例2: 使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定
义标志位.

Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记.

2eedade3b5ca4546876ad44db6b7f41b.png

使用 thread 对象的 interrupted() 方法通知线程结束.

public class ThreadDemo {
  private static class MyRunnable implements Runnable {
    @Override
    public void run() {
      // 两种方法均可以
      while (!Thread.interrupted()) {
      //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()
              + ": 有内鬼,终止交易!");
          // 注意此处的 break
          break;
       }
     }
      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(10 * 1000);
    System.out.println(Thread.currentThread().getName()
        + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
    thread.interrupt();
 }
}

thread 收到通知的方式有两种

  1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除中断标志
  • 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择
    忽略这个异常, 也可以跳出循环结束线程.

2. 否则,只是内部的一个中断标志被设置,thread 可以通过

  • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
  • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

等待一个线程

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

public class ThreadDemo {
  public static void main(String[] args) throws InterruptedException {
    Runnable target = () -> {
      for (int i = 0; i < 10; i++) {
        try {
          System.out.println(Thread.currentThread().getName()
                   + ": 我还在工作!");
          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("王五工作结束了");
 }
}

6f2371decebe4facabc268547fb3a378.png

获取当前线程引用

方法:public static Thread currentThread(); 

说明:返回当前线程对象的引用

public class ThreadDemo {
  public static void main(String[] args) {
    Thread thread = Thread.currentThread();
    System.out.println(thread.getName());
 }
}

休眠当前线程

也是我们比较熟悉一组方法,有一点要记得,因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的。

public static void sleep(long millis) throws InterruptedException

休眠当前线程 millis毫秒

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

可以更高精度的休眠

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/895087.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《深空彼岸》TXT完整版下载,知轩藏书校对版!

【内容简介】&#xff1a;   浩瀚的宇宙中&#xff0c;一片星系的生灭&#xff0c;也不过是刹那的斑驳流光。仰望星空&#xff0c;总有种结局已注定的伤感&#xff0c;千百年后你我在哪里&#xff1f;家国&#xff0c;文明火光&#xff0c;地球&#xff0c;都不过是深空中的一…

2024 年 9 月区块链游戏研报:行业回暖,Telegram 游戏引发热潮

作者&#xff1a;Stella L (stellafootprint.network) 数据来源&#xff1a;Footprint Analytics Games Research Page 9 月份&#xff0c;区块链游戏代币的市场总值增长了 29.2%&#xff0c;达到 232 亿美元&#xff0c;日活跃用户&#xff08;DAU&#xff09;数量上升了 1…

C++进阶:AVL树实现

目录 一.AVL的概念 二.AVL的实现 2.1AVL树的结构 2.2AVL树的插入 2.2.1AVL树插入一个值的大概过程 2.2.2平衡因子更新 2.2.3插入节点及更新平衡因子的实现 2.3旋转 2.3.1旋转的原则 2.3.2右单旋 2.3.3右单旋的代码实现 2.3.4左单旋 2.3.5左单旋的代码实现 2.3.6…

腾讯云宝塔面板前后端项目发版

后端发版 1. 打开“网站”页面&#xff0c;找到java项目&#xff0c;点击状态暂停服务 2.打开“文件”页面&#xff0c;进入jar包目录&#xff0c;删除原有的jar包&#xff0c;上传新jar包 3. 再回到第一步中的网站页面&#xff0c;找到jar项目&#xff0c;启动项目即可 前端发…

项目一:3-8译码器的设计与实现(FPGA)

本文以Altera公司生产的Cyclone IV系列的EP4CE15F17C8为主芯片的CRD500开发板作为项目的硬件实现平台&#xff0c;并以Quarter 18.1和ModelSim为开发工具和仿真工具。 目录 一、3-8译码器工作原理 二、设计步骤 1、创建工程文件夹和编辑设计文件 &#xff08;1&#xff09;…

微信小程序上传组件封装uploadHelper2.0使用整理

一、uploadHelper2.0使用步骤说明 uploadHelper.js ---上传代码封装库 cos-wx-sdk-v5.min.js---腾讯云&#xff0c;对象存储封装库 第一步&#xff0c;下载组件代码&#xff0c;放置到自己的小程序项目中 第二步、 创建上传对象&#xff0c;执行选择图片/视频 var _this th…

【成长day】SuperPointSuperGlue(02): Superglue论文算法学习与对应源码解析

论文工作地址&#xff1a;https://psarlin.com/superglue/ 论文地址&#xff1a;https://arxiv.org/abs/1911.11763 讲解PPT&#xff1a;https://psarlin.com/superglue/doc/superglue_slides.pdf 论文源码&#xff1a;https://github.com/magicleap/SuperGluePretrainedNetwor…

WebRTC音频 03 - 实时通信框架

WebRTC音频01 - 设备管理 WebRTC音频 02 - Windows平台设备管理 WebRTC音频 03 - 实时通信框架(本文) WebRTC音频 04 - 关键类 WebRTC音频 05 - 音频采集编码 一、前言&#xff1a; 前面介绍了音频设备管理&#xff0c;并且以windows平台为例子&#xff0c;介绍了ADM相关的类…

【分立元件】方形贴片固定电阻器制造流程

方形贴片固定电阻器是怎么制造的呢?我们在文章【分立元件】电阻的基础知识中介绍到电阻器中的固定电阻器,其品种有贴片电阻器。 贴片电阻器如下所示&#

vuex的store应用

1.在pakage.json加一行 2.和main同级别加一个js文件 import Vue from vue import Vuex from vuexVue.use(Vuex)export default new Vuex.Store({state: {langFlag: new Date().getTime()},mutations: {setLangFlag(state) {state.langFlag new Date().getTime()}} })3.在mai…

Shiro框架——shiro的认证

基本使用 1.环境搭建 引入pom依赖 说明&#xff1a;Shiro获取权限相关信息可以通过数据库获取&#xff0c;也可以通过ini配置文件获取 这里演示从ini文件中获取。 在resources目录下创建ini文件注&#xff1a;这里等号左边的(如&#xff1a;zhangsan)&#xff0c;就代表用户…

STM32--基于STM32F103C8T6的OV7670摄像头显示

本文介绍基于STM32F103C8T6实现的OV7670摄像头显示设计&#xff08;完整资源及代码见文末链接&#xff09; 一、简介 本文实现的功能&#xff1a;基于STM32F103C8T6实现的OV7670摄像头模组实时在2.2寸TFT彩屏上显示出来 所需硬件&#xff1a; STM32F103C8T6最小系统板、OV76…

学习docker第三弹------Docker镜像以及推送拉取镜像到阿里云公有仓库和私有仓库

docker目录 1 Docker镜像dockers镜像的进一步理解 2 Docker镜像commit操作实例案例内容是ubuntu安装vim 3 将本地镜像推送至阿里云4 将阿里云镜像下载到本地仓库5 后记 1 Docker镜像 镜像&#xff0c;是docker的三件套之一&#xff08;镜像、容器、仓库&#xff09;&#xff0…

大模型~合集14

我自己的原文哦~ https://blog.51cto.com/whaosoft/12286799 # Attention as an RNN Bengio等人新作&#xff1a;注意力可被视为RNN&#xff0c;新模型媲美Transformer&#xff0c;但超级省内 , 既能像 Transformer 一样并行训练&#xff0c;推理时内存需求又不随 token 数线性…

基于因果推理的强对流降水临近预报问题研究

我国地域辽阔&#xff0c;自然条件复杂&#xff0c;灾害性天气种类繁多&#xff0c;地区差异性大。雷雨大风、冰雹、短时强降水等强对流天气是造成经济损失、危害生命安全最严重的一类灾害性天气。由于强对流降水具有高强度、小空间尺度等特点&#xff0c;一直是气象预报领域的…

vue组件传值之$attrs

1.概述&#xff1a;$attrs用于实现当前组件的父组件&#xff0c;向当前组件的子组件通信&#xff08;祖-》孙&#xff09; 2.具体说明&#xff1a;$attrs是一个对象&#xff0c;包含所有父组件传入的标签属性。 注意&#xff1a;$attrs会自动排除props中声明的属性&#xff0…

矩阵系统哪家好~矩阵短视频运营~怎么矩阵OEM

一、引言 在当今的数字化时代&#xff0c;矩阵系统在众多领域中发挥着至关重要的作用&#xff0c;如视频监控、信号切换、自动化控制等。然而&#xff0c;如何判断一个矩阵系统是否好用成为了许多用户面临的问题。本文将从多个方面探讨矩阵系统好用与否的判断标准&#xff0c;希…

Python | Leetcode Python题解之第492题构造矩形

题目&#xff1a; 题解&#xff1a; class Solution:def constructRectangle(self, area: int) -> List[int]:w int(sqrt(area))while area % w:w - 1return [area // w, w]

QtCreator14调试Qt5.15出现 Launching Debugger 错误

1、问题描述 使用QtCreator14调试程序&#xff0c;Launching Debugger 显示红色&#xff0c;无法进入调试模式。 故障现象如下&#xff1a; 使能Debugger Log窗口&#xff0c;显示&#xff1a; 325^error,msg"Error while executing Python code." 不过&#xff…

SpringCloud学习:Seata总结与回顾

SpringCloud学习&#xff1a;Seata总结与回顾 文章目录 SpringCloud学习&#xff1a;Seata总结与回顾1. Seata实战&#xff1a;测试2. Seate原理总结和面试题3. Seata总结与回顾4. 易混点 1. Seata实战&#xff1a;测试 测试问题 未启用分布式事务 若不使用分布式事务&#xf…