这里写目录标题
一、java线程运行状态
在Arthas的线程面板中,你可以看到Java线程的各种状态。这些状态主要包括以下几种:
- NEW:这是线程刚刚被创建时的状态。在这个状态中,线程还没有开始执行。此状态的线程不会被执行,也不会占用CPU或内存资源。
- RUNNABLE:这个状态表示线程正在Java虚拟机中运行。这并不意味着线程一定在执行,而是说它正在占用CPU资源或者正在等待CPU资源。此状态的线程可能会占用CPU资源,因为它们是准备执行的。它们并不一定会占用大量的内存,除非它们正在执行的任务需要大量的内存。
- BLOCKED:当线程试图获取一个内部的对象锁(不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入BLOCKED状态。当持有锁的线程释放锁,BLOCKED状态的线程将有机会变成RUNNABLE状态。此状态的线程不会占用CPU资源,因为它们正在等待获取锁。它们也不会占用大量的内存,除非它们正在执行的任务需要大量的内存。
- WAITING:线程通过调用别的线程的 join()、wait()、LockSupport.park() 或 LockSupport.parkNanos() 方法,或者等待 java.util.concurrent - Lock或Condition时,进入这个状态。此状态的线程不会占用CPU资源,因为它们正在等待其他线程做出行动。它们也不会占用大量的内存,除非它们正在执行的任务需要大量的内存。
- TIMED_WAIT:这是线程在等待特定时间或者某个条件成立时的状态。当调用了如Thread.sleep(),Object.wait(long timeout),Thread.join(long millis),LockSupport.parkNanos(),或者等待 java.util.concurrent - Lock或Condition(带有超时时间)时,线程将进入这个状态。
- TIMED_WAITING:线程正在等待某个条件或者指定的时间,在这期间线程不会放弃CPU使用权。
- TERMINATED:表示线程已经执行完毕。
二、代码演示不同状态
接下来,我将通过代码示例说明在什么情况下会处于哪种状态。请注意,这些代码示例在Java环境下运行,并且你可以通过调试工具追踪线程的状态。
1. NEW状态:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 线程执行的代码
}
});
在上面的代码中,我们创建了一个新的线程对象,但是还没有调用start()方法启动它。此时,线程处于NEW状态。
2. RUNNABLE状态:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 线程执行的代码
}
});
thread.start();
在上面的代码中,我们创建了一个新的线程对象,并调用start()方法启动它。此时,线程处于RUNNABLE状态,表示它正在Java虚拟机中执行。
3. BLOCKED状态:
Object lock = new Object();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
// 等待获取锁的代码
}
}
});
thread.start();
在上面的代码中,我们创建了一个新的线程对象,并在run()方法中使用synchronized关键字获取一个对象的锁。如果其他线程持有该锁,则当前线程会处于BLOCKED状态,等待获取锁。
此状态的线程不会获取CPU执行权,因为它们正在等待获取锁,而锁是由其他线程持有的。一旦锁被释放,BLOCKED状态的线程将有机会变成RUNNABLE状态,然后可以竞争CPU执行权。
4. WAITING状态:
Object lock = new Object();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
// 等待其他线程做出行动的代码
lock.wait();
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
// 通知等待的线程继续执行的代码
lock.notify();
}
}
});
thread1.start();
thread2.start();
首先,创建一个Object对象lock作为监视器(monitor)。这个对象是用于同步的,它可以确保在任何时候只有一个线程可以访问被它保护的代码区域。
thread1是一个线程,在run()方法中,它首先获取了lock对象的锁(即进入synchronized块),然后调用lock.wait()方法。wait()方法使线程进入WAITING状态,并释放lock对象的锁,这样其他线程就可以获取这个锁了。在WAITING状态的线程不会消耗CPU资源,直到它被唤醒。
thread2也是一个线程,在run()方法中,它也首先获取了lock对象的锁,然后调用lock.notify()方法。notify()方法会唤醒等待在lock对象上的某一个线程(如果有的话)。注意,这里只是唤醒一个线程,如果有多个线程在等待,具体唤醒哪一个由JVM决定。被唤醒的线程将重新获得锁,并进入RUNNABLE状态,等待CPU时间片的分配。
这段代码的运行过程如下:
thread1启动,获取lock的锁,然后调用wait()方法,进入WAITING状态,释放锁。
thread2启动,获取lock的锁,然后调用notify()方法,唤醒等待在lock上的线程(即thread1)。
thread1被唤醒,重新获得锁,进入RUNNABLE状态。
由于已经没有其他线程在运行,所以thread1将继续执行,直到结束。
这种方式虽然简单,但很容易造成死锁等问题,实际中更常用的是java.util.concurrent包中的工具类来进行线程间的协作。
5. TIMED_WAIT状态:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
// 等待5秒钟的代码
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
在上面的代码中,我们创建了一个新的线程,该线程在启动后将进入TIMED_WAIT状态,等待5秒钟。如果在5秒内该线程被中断,它将抛出InterruptedException异常。在等待期间,线程不会执行任何代码,并且不会占用CPU资源。
6. TERMINATED状态:
一旦线程完成其生命周期,它就会进入TERMINATED状态。这意味着线程已经执行完毕,并且不会再执行任何代码。这个状态与前面五个状态有所不同,因为它表示线程已经结束,而不是正在执行。
总结:
Arthas中的线程面板提供了线程的各种状态,包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAIT和TERMINATED。这些状态描述了线程在生命周期中的不同阶段。通过理解这些状态,可以更好地了解线程的执行过程以及可能出现的问题。
三、TIMED_WAIT、TIMED_WAITING区别及代码示例
在Java编程中,TIMED_WAIT
和TIMED_WAITING
状态都是线程生命周期中的状态,用于描述线程在等待特定条件或时间的情况。
TIMED_WAIT
状态表示线程在无限期地等待某个条件成立。当线程调用了Object.wait()
方法时,它会进入TIMED_WAIT
状态,并释放对象的锁。此时,线程会一直等待,直到其他线程调用了该对象的notify()
或notifyAll()
方法,才会重新获取锁并进入可执行状态。
以下是一个示例代码,演示了TIMED_WAIT
状态的情况:
public class TimedWaitExample {
private static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Thread 1: Waiting...");
lock.wait(); // 进入 TIMED_WAIT 状态
System.out.println("Thread 1: Resumed");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2: Notifying...");
lock.notify(); // 通知等待的线程继续执行
}
});
thread1.start();
Thread.sleep(1000); // 等待线程1进入等待状态
thread2.start();
}
}
在上面的代码中,线程1调用了lock.wait()
方法,进入TIMED_WAIT
状态,并等待其他线程的通知。线程2随后调用了lock.notify()
方法,通知线程1继续执行。当线程1收到通知后,它会重新获取锁并进入可执行状态。
另一方面,TIMED_WAITING
状态表示线程在有限时间内等待某个条件成立。当线程调用了Thread.sleep()
或Object.wait(long timeout)
方法时,它会进入TIMED_WAITING
状态,并在指定的时间内等待。如果在超时时间内条件未满足,线程将重新进入可执行状态。
以下是一个示例代码,演示了TIMED_WAITING
状态的情况:
public class TimedWaitingExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
System.out.println("Thread: Waiting for 5 seconds...");
Thread.sleep(5000); // 进入 TIMED_WAITING 状态,等待 5 秒钟
System.out.println("Thread: Resumed");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
}
在上面的代码中,线程调用了Thread.sleep(5000)
方法,进入TIMED_WAITING
状态,并在5秒钟内等待。当5秒钟过去后,线程将重新进入可执行状态,并继续执行后续的代码。
四、WAITING、BLOCKED区别及代码示例
在Java多线程编程中,WAITING
和BLOCKED
是两种线程状态,它们的区别如下:
WAITING
:线程处于等待状态,它正在等待另一个线程执行某个特定的操作,比如调用Object.wait()
、Thread.join()
或LockSupport.park()
方法。在WAITING
状态的线程不会消耗CPU资源。BLOCKED
:线程处于阻塞状态,它正在等待获取一个锁,但锁被其他线程持有。在BLOCKED
状态的线程不会消耗CPU资源。
下面是一些代码示例来说明这两种状态的区别:
WAITING
状态示例:
public class WaitingExample {
private static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Thread 1 is waiting...");
lock.wait(); // 等待其他线程通知
System.out.println("Thread 1 is resuming...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 is notifying...");
lock.notify(); // 通知等待的线程
}
});
thread1.start();
Thread.sleep(1000); // 让thread1先运行一会儿
thread2.start();
}
}
在上面的代码中,thread1
进入WAITING
状态,因为它调用了lock.wait()
方法。之后,thread2
调用lock.notify()
方法通知thread1
,使其从WAITING
状态变为RUNNABLE
状态。
BLOCKED
状态示例:
public class BlockedExample {
private static Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 1 is running...");
try {
Thread.sleep(5000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 is blocked...");
// thread2将一直等待,直到thread1释放锁
}
});
thread1.start();
thread2.start();
}
}
在上面的代码中,thread1
持有锁并执行了一个耗时操作,而thread2
试图获取同一个锁但失败,因此它进入BLOCKED
状态,直到thread1
释放锁。