看一块关于给线程Thread加锁的代码产生的疑惑
BLOCKED
- 创建线程T1,T2调用
start()
方法,T1,T2状态均为RUNNABLE
- 若T1获得锁,T1状态为
RUNNABLE
,T2状态变为BLOCKED
- 等待T1执行完释放锁,T2获得锁,T2状态
RUNNABLE
class BlockThread extends Thread {
private String name; //当前线程名称
private Object lock; //锁
public BlockThread(Object lock,String name){
this.lock = lock;
this.name = name;
}
@Override
public void run() {
System.out.println("Thread "+name+" State is "+Thread.currentThread().getState());
synchronized (lock) {
System.out.println("Thread "+name+" hold the lock");
try {
System.out.println("Thread "+name+" State is "+Thread.currentThread().getState());
Thread.sleep(1000 * 10); //抢到锁的线程执行逻辑,这里用睡眠模拟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + name + " release the lock");
}
}
}
public class Test{
public static void main(String[] args) throws Exception{
Object lock = new Object();//锁
BlockThread t1 = new BlockThread(lock,"T1");
BlockThread t2 = new BlockThread(lock,"T2");
t1.start(); //线程 T1开始运行
t2.start(); //线程 T2开始运行
Thread.sleep(100); //阻塞主线程,等待T1,T2抢锁
System.out.println("Thread T1 State is " + t1.getState()); //获取T1线程状态
System.out.println("Thread T2 State is " + t2.getState()); //获取T2线程状态
}
}
输出结果
Thread T1 State is RUNNABLE
Thread T1 hold the lock
Thread T1 State is RUNNABLE
Thread T2 State is RUNNABLE
Thread T1 State is TIMED_WAITING
Thread T2 State is BLOCKED
Thread T1 release the lock
Thread T2 hold the lock
Thread T2 State is RUNNABLE
Thread T2 release the lock
疑惑一:如何区分TIMED_WAITING和WAITING
*Thread.sleep(long millis) 使当前线程暂停执行指定的时间。因为这个时间是已知的,所以状态是 TIMED_WAITING(它意味着线程正在等待,但有一个明确的时间限制)。
*而 Object.wait() 方法会导致线程进入 WAITING 状态,因为它会使线程无限期地等待,直到它被通知或被中断。也有一个 Object.wait(long timeout) 方法,它会导致线程进入TIMED_WAITING 状态,因为它有一个时间限制。
所以,TIMED_WAITING 和 WAITING 的主要区别是,前者有一个明确的等待时间,而后者没有。当你调用 Thread.sleep(), 你明确地告诉线程等待指定的毫秒数,所以它进入 TIMED_WAITING 状态
疑惑二:因为看到Thread T2没有在T1结束后输出TIMED_WAITING,天真的怀疑是不是synchronized锁是否执行了1次后就没用了
T2是进入了与T1完全相同的synchronized块。synchronized块不是一次性的;它可以由任何线程多次进入,只要该线程拥有锁。在这种情况下,T1和T2都将轮流执行相同的synchronized块。
疑惑三:那为什么最后T2没有输出TIME_WAITING的State?
但在main方法中,只是在T1和T2启动后稍微暂停了一会儿(Thread.sleep(100))来检查并打印线程状态。
这时,T1可能还在睡眠或即将完成,并且T2可能刚刚开始它的synchronized块或即将开始。
为了确实看到T2的TIMED_WAITING状态,需要确保在T1释放锁之后,还有足够的时间让T2进入其synchronized块并开始睡眠。可以通过在主线程中加入更长的睡眠来实现这一点,
例如Thread.sleep(1000 * 11)
这将确保在打印状态之前,T1已经完成了它的synchronized块并且T2已经开始它的睡眠。 所以,是的,如果你想在主程序中看到T2的TIMED_WAITING状态,你需要让主程序等待与锁块中的sleep时间相同或更长的时间,然后再打印T2的状态。
主线程和你创建的其他线程(如T1和T2)都是并发运行的。它们可以交替运行,具体取决于操作系统的线程调度。 因此,你的主程序(或主线程)在执行Thread.sleep(100)时,T1和T2仍然在后台运行。当主线程在休眠时,T1和T2还在执行它们的任务