关于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多线程如何正确暂停的理解的主要内容,如果未能解决你的问题,请参考以下文章