【Java 并发编程】线程的基本使用(持续更新优化)
目录
一、Thread
1.1 构造方法
1.2 核心属性
二、线程的操作方法
2.1 启动线程
2.2 线程中断机制
2.2.1 线程中断机制
2.2.2 中断线程的常见方式
2.2.2.1 使用自定义的标志位结合 volatile 实现
2.2.2.2 通过 AtomiucBoolean 进行中断
2.2.2.3 interrupted
2.2.2.4 isInterrupted
2.2.4 线程中断的注意事项
2.3 线程等待
2.4 获取当前线程引用
2.5 线程休眠暂停执行
2.6 线程让步
三、线程的进阶使用方式
3.1 线程中断 LockSupport
3.1.1 线程等待和唤醒的方法
3.1.2 Object的线程等待唤醒机制
3.1.3 Condition的线程等待唤醒机制
3.1.4 LockSupport 的线程阻塞和唤醒
3.1.5 LockSupport 方法介绍
一、Thread
Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。
1.1 构造方法
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");
name参数,是给线程起了一个名字。这里的名字,不影响程序执行,只是方便咱们在调试的时候,快速找到咱们关心的线程。 |
1.2 核心属性
- ID 是线程的唯一标识,不同线程不会重复
- 名称是各种调试工具用到
- 状态表示线程当前所处的一个情况,下面我们会进一步说明
- 优先级高的线程理论上来说更容易被调度到
- 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。也就是说前台线程会阻止java进程结束,后台进程不会阻止进程的结束。创建的线程默认是前台的,可以通过setDaemon设置为后台的。
- 是否存活,即简单的理解,为 run 方法是否运行结束了
- 线程的中断问题,下面我们进一步说明
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());
}
二、线程的操作方法
2.1 启动线程
在系统中真正创建出线程需要如下步骤,而系统 API start 方法会在系统内核将对应任务进行创建:
|
启动线程的步骤如下:
- 重写 run 方法:确定线程的业务逻辑
- 调用 start 方法:让线程独立执行
2.2 线程中断机制
2.2.1 线程中断机制
一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止,自己来决定自己的命运。所以Thread.stop、Thread.suspend、Thread.resume都已经被废弃了。 |
线程中断机制:在Java中没有办法立即停止一条线程,然后停止线程却显得尤为重要,如取消一个耗时操作。因此,Java中提供了一种用于停止线程的协商机制(中断),也即中断表示协商机制。Java并没有给中断增加任何语法,中断的过程完全需要自己实现。
若要中断一个线程,你需要手动调用该线程的 interrupt 语法,该方法也仅仅是将线程对象的中断标识设置为 true,接着你需要自己写代码不断检查当前的线程的标识位,如果为 true ,表示别的线程请求这条线程中断,此时究竟该做什么需要程序员写代码实现。
每个线程对象中都有一个中断标识位,用于表示线程是否被中断。该标识位为 true 表示中断,为 false 表示未中断。通过调用线程对象的 interrupt 方法将该线程的标识位设置为 true,可以在别的线程中调用,也可以在自己的线程中调用。
2.2.2 中断线程的常见方式
- 通过共享的标记位来进行线程间通信
- volatile 修饰的变量保证内存可见性
- AtomicBoolean 原子类保证原子性及内存可见性
- 通过 interrupt 方法进行线程间通知:仅仅设置现成的中断状态为 true,发起一个协商而不会立刻停止线程。
- interrupted:判断线程是否被中断(返回当前线程的中断状态)并清除当前中断状态(设置为false)
- 有可能两次调用的结果是不同的
- isInterrupted:判断当前线程是否被中断
2.2.2.1 使用自定义的标志位结合 volatile 实现
public class InterruptDemo {// 保证内存可见性static volatile boolean isStop = false;public static void main(String[] args) {new Thread(()->{while(true){if(isStop){System.out.println(Thread.currentThread().getName()+"\t"+"stop");break;}System.out.println("Hello");}},"t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}new Thread(()->{isStop = true;},"t2").start();}
}
注意事项:
|