java 线程的interrupt和sleep、wait

一、线程的interrupted:

一个正在运行的线程除了正常的时间片中断之外,能否被其他线程控制?或者说其他线程能否让指定线程放弃CPU或者提前结束运行? 除了线程同步机制之外,还有两种方法:
 (1) Thread.stop(), Thread.suspend(), Thread.resume() 和Runtime.runFinalizersOnExit() 这些终止线程运行的方法 。这些方法已经被废弃,使用它们是极端不安全的。
 (2) Thread.interrupt() 方法是很好的选择。但是使用的时候我们必须好好理解一下它的用处。

1、无法中断正在运行的线程代码 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class TestRunnable implements Runnable{
public void run(){
while(true)
{
System.out.println( "Thread is running..." );
long time = System.currentTimeMillis();//去系统时间的毫秒数
while((System.currentTimeMillis()-time < 1000)) {
//程序循环1秒钟,不同于sleep(1000)会阻塞进程。
}
}
}
}
public class ThreadDemo{
public static void main(String[] args){
Runnable r=new TestRunnable();
Thread th1=new Thread(r);
th1.start();
th1.interrupt();
}
}

  

//运行结果:一秒钟打印一次Thread is running...。程序没有终止的任何迹象
上面的代码说明interrupt()并没有中断一个正在运行的线程,或者说让一个running中的线程放弃CPU。那么interrupt到底中断什么。

首先我们看看interrupt究竟在干什么?当我们调用th1.interrput()的时候,线程th1的中断状态(interrupted status) 会被置位。我们可以通过Thread.currentThread().isInterrupted() 来检查这个布尔型的中断状态。


2、通过Thread.currentThread().isInterrupted() 来检查这个布尔型的中断状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Interrupted的经典使用代码
public void run(){
try{
....
while(!Thread.currentThread().isInterrupted()&& more work to do){
// do more work;
}
}catch(InterruptedException e){
// thread was interrupted during sleep or wait
}
finally{
// cleanup, if required
}
}

  


很显然,在上面代码中,while循环有一个决定因素就是需要不停的检查自己的中断状态。当外部线程调用该线程的interrupt 时,使得中断状态置位。这是该线程将终止循环,不在执行循环中的do more work了。这说明: interrupt中断的是线程的某一部分业务逻辑,前提是线程需要检查自己的中断状态(isInterrupted())。

3、但是当th1被阻塞的时候,比如被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞时。调用它的interrput()方法。可想而知,没有占用CPU运行的线程是不可能给自己的中断状态置位的。这就会产生一个InterruptedException异常。

 

 

//中断一个被阻塞的线程代码

复制代码
class TestRunnable implements Runnable{ 
public void run(){ 
try{ 
Thread.sleep(1000000); //这个线程将被阻塞1000秒 
}catch(InterruptedException e){ 
e.printStackTrace(); 
//do more work and return. 
} 
} 
} 
public class TestDemo2{ 
public static void main(String[] args) { 
Runnable tr=new TestRunnable(); 
Thread th1=new Thread(tr); 
th1.start(); //开始执行分线程 
while(true){ 
th1.interrupt(); //中断这个分线程 
} 
} 
} 
/*运行结果: 
java.lang.InterruptedException: sleep interrupted 
at java.lang.Thread.sleep(Native Method) 
at TestRunnable.run(TestDemo2.java:4) 
at java.lang.Thread.run(Unknown Source)*/
复制代码

 

二、sleep和wait区别:

1. 这两个方法来自不同的类,sleep方法属于Thread,wait方法属于Object。
2. 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3. wait, notify和notifyAll只能在同步控制方法(synchronized)或者同步控制块里面使用,而sleep可以在任何地方使用。

一个线程对象调用了sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在 sleep的过程中过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。

一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程。如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。从而使线程所在对象中的其它synchronized数据可被别的线程使用。 wait()方法也同样会在wait的过程中有可能被其他对象调用interrupt()方法而产生InterruptedException,效果以及处理方式同sleep()方法。

补充:可以使用guava的下面方式进行无interrupt的sleep

Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
 

posted @   w'c's  阅读(732)  评论(0编辑  收藏  举报
编辑推荐:
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
阅读排行:
· 为DeepSeek添加本地知识库
· 精选4款基于.NET开源、功能强大的通讯调试工具
· DeepSeek智能编程
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
历史上的今天:
2019-06-16 java_设计模式_装饰设计模式
点击右上角即可分享
微信分享提示