关于java多线程如何正确暂停的理解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于java多线程如何正确暂停的理解相关的知识,希望对你有一定的参考价值。

java中暂停线程使用suspend()方法,恢复线程使用resume()方法。

先看看它们如何使用:

 1 public class MyThread extends Thread {
 2     private long i = 0;
 3     @Override
 4     public void run() {
 5         while (true) {
 6             i++;
 7         }
 8     }
 9     public long getI() {
10         return i;
11     }
12     public void setI(long i) {
13         this.i = i;
14     }
15 }
 1 public class Run {
 2     public static void main(String[] args) {
 3         try {
 4             MyThread myThread = new MyThread();
 5             myThread.start();
 6             Thread.sleep(5000);
 7             // A part
 8             myThread.suspend();// 暂停
 9             System.out.println("A1"+System.currentTimeMillis()+",i:"+myThread.getI());
10             Thread.sleep(5000);
11             System.out.println("A2"+System.currentTimeMillis()+",i:"+myThread.getI());
12             
13             myThread.resume();// 恢复
14             // B part
15             myThread.suspend();// 暂停
16             System.out.println("B1"+System.currentTimeMillis()+",i:"+myThread.getI());
17             Thread.sleep(5000);
18             System.out.println("B2"+System.currentTimeMillis()+",i:"+myThread.getI());
19             
20             myThread.resume();// 恢复
21             // C part
22             myThread.suspend();// 暂停
23             System.out.println("C1"+System.currentTimeMillis()+",i:"+myThread.getI());
24             Thread.sleep(5000);
25             System.out.println("C2"+System.currentTimeMillis()+",i:"+myThread.getI());
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29     }
30 }
A11490340612430,i:1940218408
A21490340617430,i:1940218408
B11490340617430,i:1940218408
B21490340622430,i:1940218408
C11490340622430,i:1940218408
C21490340627431,i:1940218408

但是使用suspend和resume方法也有缺点,一点可能就是造成公共的同步对象的独占,使得其它线程无法访问公共同步对象。

看个例子先,ab两个线程都要访问SynchObject对象的加了同步锁的printString()方法,a先进去的时候让它执行suspe方法,让它暂停并且不再恢复,看看b还能不能进入printString()方法。

 1 public class SynchObject {
 2     public synchronized void printString() throws InterruptedException{
 3         System.out.println("begin");
 4         if (Thread.currentThread().getName().equals("a")) {
 5             System.out.println("a线程永远被suspend了!");
 6             Thread.currentThread().suspend();
 7         }
 8         System.out.println("end");
 9     }
10 }
 1 public class Run {
 2     public static void main(String[] args) throws InterruptedException {
 3         final SynchObject object = new SynchObject();
 4         new Thread(new Runnable() {
 5             @Override
 6             public void run() {
 7                 System.out.println("a线程准备进入printString()方法");
 8                 try {
 9                     object.printString();
10                 } catch (InterruptedException e) {
11                     e.printStackTrace();
12                 }
13                 
14             }
15         },"a").start();
16         
17         Thread.sleep(5000);
18         
19         new Thread(new Runnable() {
20             @Override
21             public void run() {
22                 System.out.println("b线程想要进入printString()方法,但是进不去了。。。");
23                 System.out.println("原因是printString()方法被a线程锁定,a线程执行了suspend方法,永远暂停在那儿了。。。");
24                 try {
25                     object.printString();
26                 } catch (InterruptedException e) {
27                     e.printStackTrace();
28                 }
29                 
30             }
31         },"b").start();
32     }
33 }
a线程准备进入printString()方法
begin
a线程永远被suspend了!
b线程想要进入printString()方法,但是进不去了。。。
原因是printString()方法被a线程锁定,a线程执行了suspend方法,永远暂停在那儿了。。。

对于这个占用资源的问题,还有一个很好的例子,我觉得很有必要拿出来看看,这是一个“坑”,

1 public class MyThread extends Thread {
2     private long i = 0;
3     @Override
4     public void run() {
5         while (true) {
6             i++;
7         }
8     }
9 }
1 public class Run {
2     public static void main(String[] args) throws InterruptedException {
3         MyThread myThread = new MyThread();
4         myThread.start();
5         Thread.sleep(1000);
6         myThread.suspend();
7         System.out.println("main end...");
8     }
9 }
main end...

这款代码看着没什么问题,但是如果我们在while循环里面打印出每次的i值,像这样

 1 public class MyThread extends Thread {
 2     private long i = 0;
 3     @Override
 4     public void run() {
 5         while (true) {
 6             i++;
 7             System.out.println(i);// 这是重点
 8         }
 9     }
10 }

再看看结果

技术分享

打印到一定的值它就不打印了,但是eclipse的console状态还是红色的,说明线程没结束,另外main end也没有打印,这是为什么呢?只是加了一行System.out.println()最普通的代码,其实问题就出在这个方法里,可以翻开jdk源码,看看它的实现

技术分享

可以看到内部是加了同步锁的,这就好理解了,main方法里线程启动,然后执行,然后睡眠1秒,然后执行suspend暂停线程,在这1秒之前while循环一直正常可以打印数字,当执行到suspend时,线程暂停,但是由于println方法内部加了同步锁,线程又一直处于暂停状态,所以它就永远僵在这儿了,后面的数字由于线程暂停了肯定不会打印了,由于它又同时占用着println方法的同步资源,所以导致main end也不会被打印。

上面两个例子是suspend用的不好可能会独占公共资源的问题,它还有一个问题就是suspend方法与resume方法可能不同步

 1 public class MyObject {
 2     private String username = "1";
 3     private String password = "11";
 4     
 5     public void setvalue(String uname,String pwd){
 6         this.username = uname;
 7         if (Thread.currentThread().getName().equals("a")) {
 8             System.out.println("a线程被暂停了。。。");
 9             Thread.currentThread().suspend();
10         }
11         this.password = pwd;
12     }
13     
14     public void printstr(){
15         System.out.println(username+"//"+password);
16     }
17 }
 1 public class Run {
 2     public static void main(String[] args) throws InterruptedException {
 3         final MyObject myObject = new MyObject();
 4         
 5         new Thread(new Runnable() {
 6             @Override
 7             public void run() {
 8                 myObject.setvalue("a", "aa");
 9             }
10         },"a").start();
11         
12         Thread.sleep(500);
13         
14         new Thread(new Runnable() {
15             @Override
16             public void run() {
17                 myObject.printstr();
18             }
19         },"b").start();
20     }
21 }

技术分享

 

以上是关于关于java多线程如何正确暂停的理解的主要内容,如果未能解决你的问题,请参考以下文章

Java实现多线程断点下载(下载过程中可以暂停)

多线程系列之 关于Java多线程的个人理解

Java 并发编程解析 | 如何正确理解Java领域中的多线程模型,主要用来解决什么问题?

如何正确暂停/停止线程?

Java多线程程序休眠暂停与停止

Java如何实现线程的暂停和重新启用?求大神