java多线程基础api使用
isInterrupted和interrupted的区别
isInterrupted只会返回线程状态并不改变,而interrupted会重置状态,
public class MyThread11 extends Thread{ public static void main(String[] args) throws InterruptedException { Thread.currentThread().interrupt(); System.out.println("是否停止?"+Thread.currentThread().isInterrupted()); System.out.println("是否停止?"+Thread.interrupted()); System.out.println("是否停止?"+Thread.interrupted()); } }
输出为:
是否停止?true 是否停止?true 是否停止?false
如何停止线程:
1,使用interrupt()和isInterrupted()方法组合判断,return或者捕获异常终止
注意使用interrupt()方法,无法停止线程
public class MyThread11 extends Thread{ public static void main(String[] args) throws InterruptedException { MyThread11 mt=new MyThread11(); mt.start(); Thread.sleep(500); mt.interrupt(); System.out.println("是否停止1?"+mt.isInterrupted()); System.out.println("是否停止1?"+mt.isInterrupted()); } public void run(){ for(int i=0;i<10_0000;i++){ if(this.isInterrupted()){ System.out.println("interrupted状态,退出!"); } System.out.println("i="+i); // Thread.sleep(1000); } System.out.println("for 下面"); } }
输出为:后面的还在执行
interrupted状态,退出! i=95164 interrupted状态,退出! i=95165
所以使用抛异常,捕获的方式,终止线程后续语句
public class MyThread11 extends Thread{ public static void main(String[] args) throws InterruptedException { MyThread11 mt=new MyThread11(); mt.start(); Thread.sleep(500); mt.interrupt(); System.out.println("是否停止1?"+mt.isInterrupted()); System.out.println("是否停止1?"+mt.isInterrupted()); } public void run(){ try{ for(int i=0;i<10_0000;i++){ if(this.isInterrupted()){ System.out.println("interrupted状态,退出!"); throw new InterruptedException("手动抛异常"); } System.out.println("i="+i); // Thread.sleep(1000); } System.out.println("for 下面"); }catch(InterruptedException e){ e.printStackTrace(); } } }
i=84326 interrupted状态,退出! 是否停止1?true 是否停止1?true java.lang.InterruptedException: 手动抛异常 at MyThread11.run(MyThread11.java:15)
所以interrupt()中断线程,并不能中断线程的执行,只是改变这个状态,
需要添加判断,再手动抛异常终止,
或者使用return 停止后续语句执行,如下面:
public class InterruptWithReturn extends Thread{ private int i=0; public static void main(String[] args) throws InterruptedException { InterruptWithReturn mt=new InterruptWithReturn(); mt.start(); Thread.sleep(200); mt.interrupt(); } public void run(){ while(true){ if(this.isInterrupted()){ System.out.println("stoped by interrupt"); break; } i++; System.out.println(i); } } }
另外当sleep方法在执行的时候,遇到interrupt也会报异常,可以捕获,后续的语句也无法执行到
/** * *先interrupt中断循环,再进入sleep的catch语句 */ public class MyThread13 extends Thread{ public static void main(String[] args) throws InterruptedException { MyThread13 mt=new MyThread13(); mt.start(); // Thread.sleep(500); mt.interrupt(); System.out.println("是否停止1?"+mt.isInterrupted()); System.out.println("是否停止1?"+mt.isInterrupted()); } public void run(){ try { for(int i=0;i<50_000;i++){ System.out.println(i); } Thread.sleep(20000); System.out.println("after sleep"); } catch (InterruptedException e) { System.out.println("先中断,for循环继续,直到遇到sleep方法,捕获到异常,才停止" +this.isInterrupted()); e.printStackTrace(); } } }
49998 49999 先中断,for循环继续,直到遇到sleep方法,捕获到异常,才停止false java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at MyThread13.run(MyThread13.java:19)
2,stop()方法强行停止
不推荐的原因是强行stop会导致线程结束的一些清理工作不会执行,比如对锁定对象的解锁,导致不同步,另外stop.suspend.resume三个方法已经deprecate了,后续将不再支持.
3,使用额外标记停止
利用线程通信,添加判断,适当时机停止线程
public class MyThread16 extends Thread{ private boolean isRun=true; public boolean isRun() { return isRun; } public void setRun(boolean isRun) { this.isRun = isRun; } public static void main(String[] args) throws InterruptedException { MyThread16 mt=new MyThread16(); mt.start(); Thread.sleep(100); if(mt.isRun){ mt.setRun(false); } System.out.println(mt.isAlive()); System.out.println(mt.isInterrupted()); } public void run(){ while(true){ System.out.println("running..."); if(!isRun){ System.out.println("stop"); return; } } } }
suspend和resume
使用示例:
package suspendAndResume; 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(){ while(true){ i++; } } }
package suspendAndResume; public class Run { public static void main(String[] args) { try{ MyThread mt=new MyThread(); mt.start(); //A Thread.sleep(5000); mt.suspend(); System.out.println("A="+System.currentTimeMillis()+" i="+mt.getI());//A=1525146789091 i=2436609039 Thread.sleep(5000); System.out.println("A="+System.currentTimeMillis()+" i="+mt.getI());//A=1525146794091 i=2436609039 mt.resume(); Thread.sleep(5000); System.out.println("B="+System.currentTimeMillis()+" i="+mt.getI());//B=1525146799091 i=4862628335 mt.suspend(); Thread.sleep(5000); System.out.println("B="+System.currentTimeMillis()+" i="+mt.getI());//B=1525146804091 i=4862666032 }catch(InterruptedException e){ } } }
suspend和resume缺点:
1,独占
package suspendAndResume; public class SynchronizedObject { synchronized public void printString(){ System.out.println("beging---"); if(Thread.currentThread().getName().equals("a")){ System.out.println("a线程suspend"); Thread.currentThread().suspend(); } System.out.println("end---"); } }
package suspendAndResume; public class Run2 { public static void main(String[] args){ try{ final SynchronizedObject object=new SynchronizedObject(); Thread t1=new Thread(){ public void run(){ object.printString(); } }; t1.setName("a"); t1.start(); Thread.sleep(1000); Thread t2=new Thread(){ public void run(){ System.out.println("t2 尝试进入printString方法"); object.printString(); System.out.println("没有打印begin,因为printString被t1独占,且t1被suspend了"); } }; t2.start(); }catch(InterruptedException e){ e.printStackTrace(); } } }
beging--- a线程suspend t2 尝试进入printString方法
程序会一直阻塞在这里,无法进行下去.另外对println方法的独占会导致其他线程的println阻塞,
suspend造成多线程的不同步
package suspendAndResume; public class MyObject { private String username="1"; private String passwd="1111"; public void setValue(String u,String p){ this.username=u; if("a".equals(Thread.currentThread().getName())){ System.out.println("a线程suspend"); Thread.currentThread().suspend(); } this.passwd=p; } public void printUAndP(){ System.out.println(username+":"+passwd); } }
package suspendAndResume; /* * 演示suspend方法导致不同步的问题 */ public class Run4 { public static void main(String[] args) throws InterruptedException{ MyObject mo=new MyObject(); Thread t1=new Thread(){ @Override public void run(){ mo.setValue("a", "aaa"); } }; t1.setName("a"); t1.start();//a线程会一直挂起,导致程序阻塞,并且passwd还是初始的值, Thread.sleep(1000);//sleep main进程, Thread t2=new Thread(){ @Override public void run(){ mo.printUAndP(); } }; t2.start(); } }
yield
示例:
package yield; public class MyThread extends Thread { @Override public void run(){ long sum=0; long begin=System.currentTimeMillis(); for(int i=0;i<50_0000;i++){ sum+=i; // 注释后输出: // sum=124999750000 // 用时:2ms // 不注释输出: // sum=124999750000 // 用时:62ms Thread.yield(); } long end=System.currentTimeMillis(); System.out.println("sum="+sum); System.out.println("用时:"+(end-begin)+"ms"); } }
package yield; /* * 通过循环yiel的,耗时的增加,演示yield放弃cpu时间的功能, */ public class Run { public static void main(String[] args) { MyThread mt=new MyThread(); mt.start(); } }
优先级:
源码:
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
//判断是否大于10和小于0
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
//设置的线程优先级不能高于该线程所在组的最大优先级,
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
优先级有:
规律性:优先级高的的(1-10,越大优先级越高)优先获得cpu时间,
随机性:并不是优先级高的线程一定比优先级低的先执行
从表现上来说,优先级高的线程体执行的速度要快些,因为获得cpu时间多
daemon
setDaemon(true)方法设置成daemon进程,当有没有其他的非daemon进程存在时,daemon进程也就没有存在的必要,会自动结束
参考:《Java多线程编程核心技术》