【并发编程】Java线程常见方法的使用

简介: 【并发编程】Java线程常见方法的使用

本文主要讲解了以下几个内容,分别为:

方法API清单

start 与 run

sleep 与 yield

join 方法

interrupt 方法

一、方法API清单

方法名 static 功能说明 注意
start() 启动一个新线程,在新的线程运行 run 方法中的代码 启动一个新线程,在新的线程运行 run 方法中的代码start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateException
run() 新线程启动后会调用的方法 如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象,来覆盖默认行为
join() 等待线程运行结束
join(long n) 等待线程运行结束,最多等待 n 毫秒
getId() 获取线程长整型的 id id唯一
getName() 获取线程名
setName(String) 修改线程名
getPriority() 获取线程优先级
setPriority(int) 修改线程优先级 java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率
getState() 获取线程状态 Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
isInterrupted() 判断是否被打断 不会清除打断标记
isAlive() 线程是否存活(还没有运行完毕)
interrupt() 打断线程 如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除 打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;park 的线程被打断,也会设置 打断标记
interrupted() static 判断当前线程是否被打断 会清除打断标记
currentThread() static 获取当前正在执行的线程
sleep(long n) static 让当前执行的线程休眠n毫秒,休眠时让出 cpu 的时间片给其它线程
yield() static 提示线程调度器让出当前线程对CPU的使用 主要是为了测试和调试

一、线程常见方法

1.1、start 与 run方法

请先看下面这段代码

线程t1调用run方法

public static void main(String[] args) {
    Thread t1 = new Thread("t1") {
      @Override
       public void run() {
       log.debug(Thread.currentThread().getName());
       FileReader.read(Constants.MP4_FULL_PATH);
       }
  };
   t1.run();
   log.debug("do other things ...");
}

输出

19:39:14 [main] c.TestStart - main
19:39:14 [main] c.FileReader - read [1.mp4] start ...
19:39:18 [main] c.FileReader - read [1.mp4] end ... cost: 4227 ms
19:39:18 [main] c.TestStart - do other things ...

程序仍在 main 线程运行, FileReader.read() 方法调用还是同步的

线程t1调用start方法

将上述代码中的 t1.run() 改为 t1.start();

输出:

19:41:30 [main] c.TestStart - do other things ...
19:41:30 [t1] c.TestStart - t1
19:41:30 [t1] c.FileReader - read [1.mp4] start ...
19:41:35 [t1] c.FileReader - read [1.mp4] end ... cost: 4542 ms

程序在 t1 线程运行, FileReader.read() 方法调用是异步的

总结

  1. 直接调用 run 是在主线程中执行了 run,没有启动新的线程
  2. 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码

1.2、sleep 与 yield

1.2.1 sleep
  1. 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
  3. 睡眠结束后的线程未必会立刻得到执行
  4. 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
1.2.2 yield
  1. 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程
  2. 具体的实现依赖于操作系统的任务调度器
1.2.3 线程优先级
  • 线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
  • 如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用

1.3、join

分析一个问题,下面的代码执行,打印 r 是什么?

static int r = 0;
        public static void main(String[] args) throws InterruptedException {
            test1();
        }
        private static void test1() throws InterruptedException {
            log.debug("开始");
            Thread t1 = new Thread(() -> {
                log.debug("开始");
                sleep(1);
                log.debug("结束");
                r = 10;
            });
            t1.start();
            log.debug("结果为:{}", r);
            log.debug("结束");
        }
  • 因为主线程和线程 t1 是并行执行的,t1 线程需要 1 秒之后才能算出 r=10
  • 而主线程一开始就要打印 r 的结果,所以只能打印出 r=0

解决办法就是:
用 join,加在 t1.start() 之后即可

所以join方法就是等待其他线程运行结束

1.4、 interrupt 方法

interrupt 方法为打断 sleep,wait,join 的线程

这几个方法都会让线程进入阻塞状态

打断 sleep 的线程, 会清空打断状态,以 sleep 为例

private static void test1() throws InterruptedException {
            Thread t1 = new Thread(()->{
                sleep(1);
            }, "t1");
            t1.start();
            sleep(0.5);
            t1.interrupt();
            log.debug(" 打断状态: {}", t1.isInterrupted());
        }

输出:

java.lang.InterruptedException: sleep interrupted
 at java.lang.Thread.sleep(Native Method)
 at java.lang.Thread.sleep(Thread.java:340)
 at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
 at cn.itcast.n2.util.Sleeper.sleep(Sleeper.java:8)
 at cn.itcast.n4.TestInterrupt.lambda$test1$3(TestInterrupt.java:59)
 at java.lang.Thread.run(Thread.java:745)
21:18:10.374 [main] c.TestInterrupt - 打断状态: false

打断正常运行的线程, 不会清空打断状态

private static void test2() throws InterruptedException {
            Thread t2 = new Thread(()->{
                while(true) {
                    Thread current = Thread.currentThread();
                    boolean interrupted = current.isInterrupted();
                    if(interrupted) {
                        log.debug(" 打断状态: {}", interrupted);
                        break;
                    }
                }
            }, "t2");
            t2.start();
            sleep(0.5);
            t2.interrupt();
        }

输出

20:57:37.964 [t2] c.TestInterrupt - 打断状态: true


相关文章
|
2月前
|
人工智能 安全 调度
Python并发编程之线程同步详解
并发编程在Python中至关重要,线程同步确保多线程程序正确运行。本文详解线程同步机制,包括互斥锁、信号量、事件、条件变量和队列,探讨全局解释器锁(GIL)的影响及解决线程同步问题的最佳实践,如避免全局变量、使用线程安全数据结构、精细化锁的使用等。通过示例代码帮助开发者理解并提升多线程程序的性能与可靠性。
109 0
|
2月前
|
前端开发 JavaScript Java
Java 开发中 Swing 界面嵌入浏览器实现方法详解
摘要:Java中嵌入浏览器可通过多种技术实现:1) JCEF框架利用Chromium内核,适合复杂网页;2) JEditorPane组件支持简单HTML显示,但功能有限;3) DJNativeSwing-SWT可内嵌浏览器,需特定内核支持;4) JavaFX WebView结合Swing可完美支持现代网页技术。每种方案各有特点,开发者需根据项目需求选择合适方法,如JCEF适合高性能要求,JEditorPane适合简单展示。(149字)
263 1
|
2月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
127 0
|
2月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
282 83
|
2月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
230 83
|
1月前
|
算法 Java 开发者
Java 项目实战数字华容道与石头迷阵游戏开发详解及实战方法
本文介绍了使用Java实现数字华容道和石头迷阵游戏的技术方案与应用实例,涵盖GUI界面设计、二维数组操作、游戏逻辑控制及自动解法算法(如A*),适合Java开发者学习游戏开发技巧。
184 46
|
2月前
|
Java 索引
Java ArrayList中的常见删除操作及方法详解。
通过这些方法,Java `ArrayList` 提供了灵活而强大的操作来处理元素的移除,这些方法能够满足不同场景下的需求。
347 30
|
2月前
|
安全 Java API
Java 17 及以上版本核心特性在现代开发实践中的深度应用与高效实践方法 Java 开发实践
本项目以“学生成绩管理系统”为例,深入实践Java 17+核心特性与现代开发技术。采用Spring Boot 3.1、WebFlux、R2DBC等构建响应式应用,结合Record类、模式匹配、Stream优化等新特性提升代码质量。涵盖容器化部署(Docker)、自动化测试、性能优化及安全加固,全面展示Java最新技术在实际项目中的应用,助力开发者掌握现代化Java开发方法。
117 1
|
2月前
|
安全 Java API
Java 集合高级应用与实战技巧之高效运用方法及实战案例解析
本课程深入讲解Java集合的高级应用与实战技巧,涵盖Stream API、并行处理、Optional类、现代化Map操作、不可变集合、异步处理及高级排序等核心内容,结合丰富示例,助你掌握Java集合的高效运用,提升代码质量与开发效率。
192 0