停止一个线程意味着在线程处理完任务之前停止正在做的操作,也就是放弃当前的操作,虽然看起来非常简单,但是要做好防范措施。
创建文件MyThread.java:
public class MyThread extends Thread{
@Override
public void run() {
super.run();
for (int i = 0;i < 50000 ; i++){
System.out.println("i="+i);
}
}
}
创建测试类RunTest.java:
public class RunTest {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
System.out.println("ZZZZZZZZZ");
}
}
预期结果:输出50000行+ZZZZZ,实际输出50001行+zzzz
这说明了什么?调用interrupt()方法并没有真正的把线程停止。
2.2.1 public static boolean interrupted():测试currentThread()是否已经中断,执行后具有清除状态标志值为false的功能,如:第一次调用时,当前线程未中断,清除该标志在第二次调用检验中断状态之前,第二次的调用结果就为了true。
2.2.2 public boolean this.isInterrupted():测试this关键字所在类的对象是否已经中断,不清楚状态标志。
修改MyThread.java如下:
public class MyThread extends Thread{
@Override
public void run() {
super.run();
for (int i = 0;i < 50000 ; i++){
if(this.isInterrupted()){
System.out.println("我已经是停止状态了,我要退出了");
break;
}
System.out.println("i="+i);
}
}
}
修改RunTest.java如下:
public class RunTest {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(5000);
thread.interrupt();
}catch (InterruptedException e){
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
}
实际的运行结果:
i=0
i=1
end!
我已经是停止状态了,我要退出了
类MyThread修改如下:
public class MyThread extends Thread{
@Override
public void run() {
super.run();
for (int i = 0;i < 50000 ; i++){
if(this.isInterrupted()){
System.out.println("我已经是停止状态了,我要退出了");
break;
}
System.out.println("i="+i);
}
System.out.println("我被输出了,是for下的语句,线程结束后我还能执行嘿!");
}
}
实际运行结果如下,说明并没有阻止for后的语句再继续执行
i=0
i=1
i=2
end!
我已经是停止状态了,我要退出了
我被输出了,是for下的语句,线程结束后我还能执行嘿!
修改MyThread类如下:
public class MyThread extends Thread{
@Override
public void run() {
super.run();
try {
for (int i = 0;i < 50000 ; i++){
if(this.isInterrupted()){
System.out.println("我已经是停止状态了,我要退出了");
throw new InterruptedException();
}
System.out.println("i="+i);
}
System.out.println("我被输出了,是for下的语句!");
}catch (InterruptedException e){
System.out.println("进入了MyThread类的run方法中的catch了");
e.printStackTrace();
}
}
}
实际的运行结果部分如下:
i=14006
i=14007
i=14008
i=14009
我已经是停止状态了,我要退出了
end!
进入了MyThread类的run方法中的catch了
java.lang.InterruptedException
at MyThread.run(MyThread.java:10)
public class MyThread extends Thread{
@Override
public void run() {
super.run();
while(true){
if(this.isInterrupted()){
System.out.println("停止了哦!");
return;
}
System.out.println("timer:"+System.currentTimeMillis());
}
}
}
public class RunTest {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
}
最后的实际运行结果为,证明停止了之后,没有再继续往下执行
timer:1592300686447
timer:1592300686447
timer:1592300686447
timer:1592300686447
停止了哦!
在Java多线程中,可以使用suspend()来暂停线程,resume()来恢复线程的执行。
简单使用的示例:
public class MyThread extends Thread{
private long i = 0;
public long getI(){
return i;
}
public void setI(long i){
this.i = i;
}
@Override
public void run() {
super.run();
while(true){
i++;
}
}
}
我的RunTest类如下:
public class RunTest {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(5000);
//A段
thread.suspend();//此方法已过期,但是研究过期方法为什么被丢弃也是件有趣的事情
System.out.println("A="+System.currentTimeMillis()+",i="+thread.getI());
Thread.sleep(5000);
System.out.println("A="+System.currentTimeMillis()+",i="+thread.getI());
//B段
thread.resume();
Thread.sleep(5000);
//C段
thread.suspend();
System.out.println("B="+System.currentTimeMillis()+",i="+thread.getI());
Thread.sleep(5000);
System.out.println("B="+System.currentTimeMillis()+",i="+thread.getI());
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
最后的运行结果为:
A=1592302312763,i=2823139737
A=1592302317763,i=2823139737
B=1592302322763,i=5736528459 ----》此时线程已被暂停,不再执行run方法的i++
B=1592302327763,i=5736528459 ----->已被暂停的线程,未被恢复,所以i值不变的
如果suspend()方法与resume()方法使用不当,极易造成公共同步对象被占,其他线程无法访问公共对象的结果。
public class SynchronizedObject {
synchronized public void printString(){
System.out.println("begin");
if(Thread.currentThread().getName().equals("a")){
System.out.println("a线程永远被暂停了");
Thread.currentThread().suspend();
}
System.out.println("end!");
}
}
public class RunTest {
public static void main(String[] args) {
try {
final SynchronizedObject obj = new SynchronizedObject();
Thread thread1 = new Thread(){
@Override
public void run() {
obj.printString();
}
};
thread1.setName("a");
thread1.start();
Thread.sleep(1000);
Thread thread2 = new Thread(){
@Override
public void run() {
System.out.println("Thread2启动了,但却进入不了printString,无法打印出b的begin");
obj.printString();
}
};
thread2.setName("b");
thread2.start();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
实际运行结果,A线程独占并锁死了公共资源printString()方法
begin
a线程永远被暂停了
Thread2启动了,但却进入不了printString,无法打印出b的begin
public class MyThread extends Thread{
private long i = 0;
@Override
public void run() {
super.run();
while(true){
i++;
}
}
}
public class RunTest {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(1000);
thread.suspend();
System.out.println("mainEnd!");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
运行结果如下:输出mainEnd,但是可以看到进程未被销毁,在控制台看到是呈红色按钮。
但是如果将MyThread.java更改成如下:
public class MyThread extends Thread{
private long i = 0;
@Override
public void run() {
super.run();
while(true){
i++;
System.out.println(i);
}
}
}
运行结果如下:未输出mainEnd
144067
144068
144069
144070
144071
144072
144073
144074
产生这种情况的原因是:当程序运行到System.out.prtintln(i)内部时,同步锁是不释放的,println()的源代码如下:
public void println(long x){
synchronized (this){
print(x);
newLine();
}
}
以上便是多线程的暂停和彻底停止的内容,关于suspend()和resume()一起使用还可能造成数据的不完整的缺点这里就不再述说,现在JDK版本已经将这两个方法作废了,想要对线程进行暂停与恢复的处理,可使用wait(),notify()或notifyAll()方法。