Thread 状态及volatile关键字作用join方法的使用

本文详细介绍了Java中线程的五种状态:NEW、RUNNABLE、BLOCKED、TIMED_WAITING和TERMINATED,解释了每种状态的含义及线程如何在这些状态之间转换。此外还探讨了volatile关键字的作用及其对线程间数据一致性的保障。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程状态 Thread.State
1 Thread.State BLOCKED 阻塞状态

Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object.wait.
线程正在等待线程锁的阻塞状态,阻塞状态正在等待线程锁进入同步方法或者同步代码块,或者是调用该线程调用wait后等待重新进入同步方法。

2 Thread.State NEW

Thread state for a thread which has not yet started.
线程创建未开始状态

3 Thread.State RUNNABLE

Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

线程运行状态,正在运行状态的线程正在被java虚拟机执行,但是也可能正在等待来自操作系统的其他资源例如处理器。

4 Thread.State TERMINATED

Thread state for a terminated thread. The thread has completed execution.
线程终止状态,这个线程被执行完成。

5 Thread.State TIMED_WAITING

Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
Thread.sleep // sleep(long millis) or sleep(long millis, int nanos),The thread does not lose ownership of any monitors. 不会释放锁。
Object.wait with timeout
This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish
any and all synchronization claims on this object.
这个方法会引起当前线程成为等待状态,并放弃这个对象上的同步的权益,就是释放了对象锁。
Thread.join with timeout
LockSupport.parkNanos
LockSupport.parkUntil
正在等待特定时间的线程状态,一个线程处在定时定时等待状态是因为调用了如下其中之一,带有明确的指定等待时间的方法

volatile 关键字的作用 保证该数据在多线程保持一致性。

如果使用volatile修饰变量,java代码编译后,运行指令会带有lock 前缀,jvm在处理这个lock信号时会引发两个操作
1 会将缓存数据写到主内存,lock前缀指令执行执行时 会锁住缓存区域,利用缓存一致性保证原子操作,并阻止多个处理器同时修改内存数据。
2 回写主内存的操作会使其他线程缓存的该内存地址的数据失效。
根据处理器的一致性协议,处理器会嗅探总线上的传播数据来检查自己缓存的数据是否是过期了,当处理器发现缓存地址失效,
会将缓存数据设置成失效,当处理这个数据时,从主内存中重新读取。
api 注释 join()方法

/*Waits at most {@code millis} milliseconds for this thread to
die. A timeout of {@code 0} means to wait forever.
*/
最多等待这个线程死亡多少毫秒,如果参数是0,则永远等待这个线程死亡
例 A线程正在运行,b线程对象join(args)
如果args == 0.则A线程一直等到B线程执行完成再执行
如果args >0 ,则A线程等待B线程执行args 毫秒时间后继续执行

<think>在Java中,`volatile`关键字用于确保变量的可见性和有序性,但不保证原子性。它告诉编译器和运行时环境,该变量可能被多个线程同时访问,因此每次读取都应该从主内存中获取,而不是从线程的本地缓存(如CPU缓存)中读取;每次写入都应该立即刷新到主内存中。这样可以避免一个线程修改了变量值而另一个线程看不到的情况。 然而,需要注意的是,`volatile`并不能保证复合操作(如自增操作)的原子性。对于原子性操作,我们通常使用`java.util.concurrent.atomic`包中的原子类,或者使用`synchronized`关键字。 下面是一个使用`volatile`关键字的经典案例:使用一个标志位来控制线程的终止。 ### 案例:使用volatile作为终止线程的标志 ```java public class VolatileExample { // 使用volatile关键字修饰标志位 private volatile boolean running = true; public void stop() { running = false; } public void run() { while (running) { // 执行任务 System.out.println("Thread is running..."); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Thread was interrupted"); } } System.out.println("Thread stopped."); } public static void main(String[] args) throws InterruptedException { VolatileExample example = new VolatileExample(); Thread thread = new Thread(example::run); thread.start(); // 主线程休眠3秒后,停止子线程 Thread.sleep(3000); example.stop(); // 等待子线程结束 thread.join(); } } ``` ### 代码解释: 1. **`volatile`变量**:`running`被声明为`volatile`,确保当主线程调用`stop()`方法将`running`设置为`false`时,子线程能立即看到这个变化,从而跳出循环,终止线程。 2. **如果没有`volatile`**:如果没有`volatile`,子线程可能因为缓存的原因,一直看不到`running`变为`false`,导致循环无法终止。 3. **线程启动与停止**:在`main`方法中,启动子线程后,主线程休眠3秒,然后调用`stop()`方法将`running`置为`false`,并等待子线程结束(`thread.join()`)。 ### 注意事项: - 这个例子中,`volatile`保证了可见性,使得对`running`的修改对所有线程立即可见。 - 但是,如果多个线程同时修改`running`(这个例子中只有一个修改线程,所以安全),并且`running`是`boolean`类型(赋值是原子操作),那么使用`volatile`是安全的。如果变量是`long`或`double`等64位变量,在32位JVM上,非`volatile`的64位操作可能被拆分为两个32位操作,从而需要`volatile`来保证原子性(但Java中对于64位的`long`和`double`,即使没有`volatile`,在大多数现代JVM上也是原子操作,但规范允许拆分为两个32位操作,所以为了可移植性,最好加上`volatile`)。 ### 另一个案例:单例模式的双重检查锁(DCL) `volatile`在双重检查锁定(Double-Checked Locking)中也是必要的,用于防止指令重排序导致的问题。 ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); } } } return instance; } } ``` ### 解释: - 如果没有`volatile`,在`instance = new Singleton();`这行代码中,由于指令重排序,可能会先分配内存空间,然后将引用赋值给`instance`,最后再初始化对象。这样,另一个线程可能在对象还没有完全初始化时就访问它,导致问题。 - `volatile`关键字禁止了指令重排序,保证了对象的初始化在赋值操作之前完成。 ### 总结: `volatile`关键字适用于: 1. 状态标志(如上面的终止标志)。 2. 双重检查锁定(DCL)的单例模式。 3. 其他需要可见性保证的场景,但注意不能保证原子性(如自增操作)。 ### 相关问题: 1. 什么时候使用volatile? 2. volatile和synchronized有什么区别? 3. 为什么双重检查锁定中需要volatile? 4. volatile能保证原子性吗?如果不能,如何保证原子性?</think>### Java 中 `volatile` 关键字使用案例 `volatile` 关键字在 Java 中用于解决多线程环境下的 **可见性问题** 和 **禁止指令重排序**。它确保: 1. **可见性**:当线程修改 `volatile` 变量时,新值立即对其他线程可见 2. **有序性**:禁止 JVM 对 `volatile` 变量的读写操作进行重排序优化 #### 经典案例:状态标志位 以下是一个使用 `volatile` 作为线程终止标志的示例: ```java public class VolatileExample { // volatile 确保 running 的修改对所有线程立即可见 private volatile boolean running = true; public void start() { new Thread(() -> { while (running) { // 循环检查 volatile 变量 System.out.println("Thread is running..."); try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } System.out.println("Thread stopped."); }).start(); } public void stop() { running = false; // 修改 volatile 变量 } public static void main(String[] args) throws InterruptedException { VolatileExample example = new VolatileExample(); example.start(); // 启动线程 Thread.sleep(2000); // 主线程等待2秒 example.stop(); // 终止子线程 } } ``` #### 代码解释: 1. **`volatile boolean running`**: - 确保主线程调用 `stop()` 修改 `running=false` 后,子线程能**立即看到**这个变化 - 若无 `volatile`,子线程可能因 JVM 优化而永远看不到 `running` 的变化 2. **工作线程**: - 通过 `while(running)` 循环检查标志位 - 收到停止信号后立即退出循环 3. **主线程流程**: - 启动工作线程后休眠 2 秒 - 调用 `stop()` 修改 `volatile` 变量 - 工作线程检测到变化后自动终止 #### 执行结果: ``` Thread is running... Thread is running... Thread is running... Thread is running... Thread stopped. // 约2秒后停止 ``` #### 使用注意事项: 1. **不保证原子性**: ```java volatile int count = 0; count++; // 这不是原子操作!需要 synchronized 或 AtomicInteger ``` 2. **适用场景**: - 状态标志(如示例) - 一次性安全发布(如双重检查锁单例模式) - 独立观察(定期更新状态值) 3. **双重检查锁单例模式中的 volatile**: ```java public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); // volatile 防止指令重排序 } } } return instance; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值