java suspend() 和 resume()_Java暂停/挂起线程(suspend())和恢复线程(resume())

暂停线程意味着此线程还可以恢复运行。在 Java 多线程中,可以使用 suspend() 方法暂停线程,使用 resume() 方法恢复线程的执行。

suspend() 与 resume() 方法

本节通过一个案例来介绍 suspend() 与 resume() 方法的用法。首先来看一下案例中使用到的 MyThread21 线程,代码如下所示。

package ch14;

public class MyThread21 extends Thread

{

private long i=0;

public long getI()

{

return i;

}

public void setI(long i)

{

this.i=i;

}

@Override

public void run()

{

while(true)

{

i++;

}

}

}

MyThread21 线程中有一个成员 i,其中 setI() 方法和 getI() 方法分别用于设置和获取 i 的值,run() 方法则是一个从i开始递增的死循环。

下面编写主线程的代码,具体如下所示。

package ch14;

public class Test25

{

public static void main(String[] args)

{

try

{

MyThread21 thread=new MyThread21();

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= 1540978346179 i= 2680986095

A= 1540978351179 i= 2680986095

B= 1540978356179 i= 5348657508

B= 1540978361179 i= 5348657508

从输出结果的时间来看,调用 suspend() 方法确实可以暂停线程,而在调用 resume() 方法后线程恢复运行状态。

独占问题

在使用 suspend() 方法与 resume() 方法时,如果使用不当极易造成公共的同步对象被独占,从而使得其他线程无法访问公共同步对象。

例 2

下面通过一个案例来演示这种情况。如下所示是案例中使用的公共对象的代码。

package ch14;

public class SynchronizedObject1

{

synchronized public void printString()

{

System.out.println("begin");

if (Thread.currentThread().getName().equals("a"))

{

System.out.println("a线程永远 suspend了!");

Thread.currentThread().suspend();

}

System.out.println("end");

}

}

SynchronizedObject1 类在 printString() 方法开始时输出“begin”,在该方法结束时输出“end”,方法体中的if判断如果当前线程的名称是 a 则调用 suspend() 方法暂停线程。

接下来编写主线程代码,在主线程中创建一个 SynchronizedObject1 类对象并在线程中调用 printString() 方法,具体代码如下所示。

package ch14;

public class Test26

{

public static void main(String[] args)

{

try

{

final SynchronizedObject1 object=new SynchronizedObject1();

Thread thread1=new Thread()

{

@Override

public void run()

{

object.printString();

}

};

thread1.setName("a");

thread1.start();

Thread.sleep(1000);

Thread thread2=new Thread()

{

@Override

public void run()

{

System.out.println("thread2启动了,但进入不了printString()方法!所以只会打印1个begin!");

System.out.println("因为printString()方法被a线程锁定并且永远暂停了!");

object.printString();

}

};

thread2.start();

}

catch(InterruptedException e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

上述代码比较简单这里就不再解释,运行后的结果如下所示。从中可以看到由于线程被永久暂停,所以只会输出一个 begin。

begin

a线程永远 suspend了!

thread2启动了,但进入不了printString()方法!所以只会打印1个begin!

因为printString()方法被a线程锁定并且永远暂停了!

例 3

还有另外一种独占锁的情况也要格外注意,稍有不慎就会掉进“坑”里。创建测试用的 MyThread22 线程,具体代码如下:

package ch14;

public class MyThread22 extends Thread

{

private long i=0;

@Override

public void run()

{

while (true)

{

i++;

}

}

}

再来看主线程的代码,如下所示。

package ch14;

public class Test27

{

public static void main(String[] args)

{

try

{

MyThread22 thread=new MyThread22();

thread.start();

Thread.sleep(1000);

thread.suspend();

System.out.println("main end!");

}

catch(InterruptedException e)

{

e.printStackTrace();

}

}

}

程序执行后将看到预料不到的结果,如下所示。

main end!

如果将 MyThread22 线程类的代码更改如下:

package ch14;

public class MyThread22 extends Thread

{

private long i=0;

@Override

public void run()

{

while(true)

{

i++;

System.out.println(i);

}

}

}

再次运行程序,控制台将不打印 main end,运行结果如下所示。

......

130862

130863

130864

130865

130866

130867

出现这种情况的原因是,当程序运行到 println() 方法内部停止时,同步锁未被释放。这导致当前 PrintStream 对象的 println() 方法一直呈“暂停”状态,并且“锁未释放”,而 main() 方法中的代码“System.out. println(Mmain end!'1);”迟迟不能执行打印。

提示:虽然 suspend() 方法是过期作废的方法,但还是有必要研究它过期作废的原因,这是很有意义的。

不同步问题

在使用 suspend() 方法与 resume() 方法时也容易出现因为线程的暂停而导致数据不同步的情况。

例 4

下面通过一个案例来演示这种情况。如下所示是案例中使用的公共对象的代码。

package ch14;

public class MyObject

{

private String username="1";

private String password="11";

public void setValue(String u,String p)

{

this.username=u;

if(Thread.currentThread().getName().equals("a"))

{

System.out.println("停止a线程!");

Thread.currentThread().suspend();

}

this.password=p;

}

public void printUsernamePassword()

{

System.out.println(username+" "+password);

}

}

如上述代码所示,MyObject 类的 setValue() 方法会在线程名称是 a 时执行停止线程操作。 如下所示是主线程代码。

package ch14;

public class Test28

{

public static void main(String[] args) throws InterruptedException

{

final MyObject myobject=new MyObject();

Thread thread1=new Thread()

{

public void run()

{

myobject.setValue("a","aa");

};

};

thread1.setName("a");

thread1.start();

Thread.sleep(500);

Thread thread2=new Thread()

{

public void run()

{

myobject.printUsernamePassword();

};

};

thread2.start();

}

}

程序运行结果如下所示。

停止a线程!

a 11

从程序运行的结果可以看到,出现了值不同步的情况,所以在程序中使用 suspend() 方法要格外注意。

相关文章

总结

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

如您喜欢交流学习经验,点击链接加入交流1群:1065694478(已满)交流2群:163560250

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值