【并发编程】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


相关文章
|
1天前
|
数据采集 安全 Java
Java并发编程学习12-任务取消(上)
【5月更文挑战第6天】本篇介绍了取消策略、线程中断、中断策略 和 响应中断的内容
20 4
Java并发编程学习12-任务取消(上)
|
1天前
|
Java
Java String 避免空指针的方法
Java String 避免空指针的方法
4 0
|
1天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第15天】本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化。我们将通过实例分析,理解线程安全的重要性,并学习如何通过各种技术和策略来实现它。同时,我们也将探讨如何在保证线程安全的同时,提高程序的性能。
|
1天前
|
存储 缓存 安全
【并发编程】线程池以及场景题
【并发编程】线程池以及场景题
8 0
|
1天前
|
存储 监控 安全
【并发编程】线程安全(下)
【并发编程】线程安全
7 0
|
1天前
|
存储 安全 Java
【并发编程】线程安全(上)
【并发编程】线程安全
9 0
|
1天前
|
Java 程序员 调度
【并发编程】线程基础知识
【并发编程】线程基础知识
6 0
|
1天前
|
Java 编译器 开发者
Java并发编程中的锁优化策略
【5月更文挑战第15天】 在Java的多线程编程中,锁机制是实现线程同步的关键。然而,不当的锁使用往往导致性能瓶颈甚至死锁。本文深入探讨了Java并发编程中针对锁的优化策略,包括锁粗化、锁消除、锁分离以及读写锁的应用。通过具体实例和性能分析,我们将展示如何有效避免竞争条件,减少锁开销,并提升应用程序的整体性能。
|
1天前
|
消息中间件 并行计算 Java
Java中的多线程编程:基础知识与实践
【5月更文挑战第15天】 在现代计算机编程中,多线程是一个复杂但必不可少的概念。特别是在Java这种广泛使用的编程语言中,理解并掌握多线程编程是每个开发者必备的技能。本文将深入探讨Java中的多线程编程,从基础概念到实际应用场景,为读者提供全面的理论支持和实践指导。
|
1天前
|
Java 程序员 调度
Java中的多线程编程:从理论到实践
【5月更文挑战第14天】在现代计算机技术中,多线程编程是一个重要的概念。它允许多个线程并行执行,从而提高程序的运行效率。本文将从理论和实践两个角度深入探讨Java中的多线程编程,包括线程的基本概念、创建和控制线程的方法,以及如何处理线程同步和通信问题。
http://www.vxiaotou.com