线程运行完成,正常中止java
执行stop方法,暴力中止,现已弃用数据库
执行interrupt方法,如今使用。ide
使用stop方法终止线程会释放掉此线程锁定的全部的监视器,若是线程修改了锁定对象的内容在尚未被正常处理以前线程被终止了。将会形成数据不一致的后果。函数
例如银行取款的例子:在线程A中进行取款操做,取款操做是一个同步方法,其中共有三个步骤:输入密码,取钱,修改余额。当用户a在输入密码,取钱以后,线程A.stop();线程终止。被修改的余额尚未写回数据库,从而形成数据混乱。测试
举例说明:首先定义一个操做类Loginthis
package com.feng.example; public class Login { private String username="a"; private String password="aa"; synchronized public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } synchronized public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } synchronized public void login(String username, String passwd) { this.username = username; try { Thread.sleep(20000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.password = passwd; } }
定义线程类,调用login方法spa
package com.feng.example; public class LoginThread extends Thread{ private Login login; public LoginThread(Login login) { this.login = login; } @Override public void run() { // TODO Auto-generated method stub super.run(); login.login("b", "bb"); } }
测试类:线程
package com.feng.example; public class LoginTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Login login = new Login(); Thread thread = new LoginThread(login); thread.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } thread.stop(); //强制终止线程 System.out.println(login.getUsername()+"========"+login.getPassword()); } }
分析:login对象的username初值为a,password初值为aa,线程thread调用login("b","bb");方法,将username的值修改成b,此时线程休眠20秒,在线程thread start以后2秒调用thread.stop,线程终止。释放掉对login对象的锁。只有释放掉对login的锁才能调用同步方法getUsername和getPassword.code
程序运行结果:对象
b========aa
使用interrupt方法,此方法只是给线程一个标记,表示此线程要被终止(只是一个标记,没有作出任何终止线程的行为),经过配合使用interrupted方法或者isInterrupted方法来检测线程是否要中止,若是检测到要中止,则先进行完相应的操做以后使用break或者return正常执行完(在有循环体的状况下)或者使用抛出异常的方式终止线程(推荐使用)
经过上述内容能够看出正确中止线程的思想就是:利用某种手段使线程正常中止或者抛出异常的方式终止线程
interrupted方法 静态方法 检测当前线程(执行这个方法的线程)是否被中断(判断有没有中断标记)
isInterrupted方法 检测调用者是否被中断
测试interrupted方法的使用,建立MyThread线程类
package com.feng.example; public class MyThread extends Thread { @Override public void run() { int i = 0; while(true) { i++; } } }
测试类:
package com.feng.example; public class ThreadTest { /** * @param args */ public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); thread.interrupt(); System.out.println(thread.interrupted()+"=========="+Thread.interrupted()); //main函数执行的这段代码,因此当前线程是main System.out.println(thread.interrupted()+"=========="+Thread.interrupted()); } }
分析:在main函数中启动thread,而后使用thread.interrupt()终止线程(其实就是打一个终止标记),而输出语句中使用的是interrupted方法,此方法检测的是当前线程,即执行这句话的线程也就是main,由于终止的是thread而不是main,因此打印出来的结果都是false。
这里由于interrupted是静态方法,使用thread.interrupted() 和Thread.interrupted()是同样的。
测试结果:
false==========false false==========false
修改上面的测试程序,使主线程终止,修改程序以下:
package com.feng.example; public class ThreadTest { /** * @param args */ public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); Thread.currentThread().interrupt(); System.out.println(thread.interrupted()+"=========="+Thread.interrupted()); //main函数执行的这段代码,因此当前线程是main System.out.println(thread.interrupted()+"=========="+Thread.interrupted()); } }
分析:如今终止的是主线程,所以在输出的时候调用thread.interrupted()输出true。由于interrupted方法具备清除中断标记的功能,所以再次调用interrupted()方法时,输出false
测试若是以下:
true==========false false==========false
修改测试程序查看isInterrupted方法的使用:
package com.feng.example; public class ThreadTest { /** * @param args */ public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); thread.interrupt(); System.out.println(thread.isInterrupted()+"=========="+thread.isInterrupted()); //main函数执行的这段代码,因此当前线程是main } }
分析:isInterrupted方法不具备清除中断标记的做用,所以两次输出都为true
运行结果:
true==========true
修改线程类
package com.feng.example; public class MyThread extends Thread { @Override public void run() { int i = 0; while(true) { if(this.interrupted()) //这里换作this.isInterrupted()也能够 { //作相应的处理 System.out.println("线程正常终止"); break; } i++; } } }
测试类代码:
package com.feng.example; public class ThreadTest { /** * @param args */ public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); thread.interrupt(); } }
当在while(true)循环中判断若是又中断则跳出循环,今后处也能够看到thread.interrupt();只是作一个中断标记,当线程检测到这个中断标记后,能够作一些必要的操做后跳出循环,正常运行完线程。
运行结果:
线程正常终止
若是上述的线程中有多个循环,break就只能跳出一个循环,从而进入另外一个循环中,仍是终止不了线程。咱们可使用return来退出循环。
先看问题:修改上述的线程类
package com.feng.example; public class MyThread extends Thread { @Override public void run() { for(int i=0; i<1000; i++) { if(this.isInterrupted()) { //作相应的处理 System.out.println("线程正常终止"); break; } i++; } System.out.println("线程还能够运行,若是我是一个循环又会进入一个循环"); } }
查看执行结果:
线程正常终止 线程还能够运行,若是我是一个循环又会进入一个循环
说明使用break的话,循环外的语句仍是会被执行的,不想让循环外的语句执行就换为return
修改线程类代码:
package com.feng.example; public class MyThread extends Thread { @Override public void run() { for(int i=0; i<1000; i++) { if(this.isInterrupted()) { //作相应的处理 System.out.println("线程正常终止"); return; } i++; } System.out.println("线程还能够运行,若是我是一个循环又会进入一个循环"); } }
运行结果以下:
线程正常终止
return通常会对代码形成污染,所以咱们仍是建议使用抛出异常的方法,来终止线程
修改线程类
package com.feng.example; public class MyThread extends Thread { @Override public void run() { try { for (int i = 0; i < 1000; i++) { if (this.isInterrupted()) { // 作相应的处理 System.out.println("线程正常终止"); throw new InterruptedException(); } i++; } System.out.println("线程还能够运行,若是我是一个循环又会进入一个循环"); } catch (InterruptedException e) { System.out.println("进入Catch"); e.printStackTrace(); } } }
运行结果:
线程正常终止 进入Catch java.lang.InterruptedException at com.feng.example.MyThread.run(MyThread.java:13)
定义线程类:
package com.feng.example; public class MyThread extends Thread { @Override public void run() { try { System.out.println("线程执行"); Thread.sleep(10000); System.out.println("线程执行完成"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //休眠10秒 } }
测试类:
package com.feng.example; public class ThreadTest { /** * @param args */ public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } thread.interrupt(); } }
终止sleep中的线程,会抛出interruptedException
运行结果:
线程执行 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.feng.example.MyThread.run(MyThread.java:10)
修改线程类:
package com.feng.example; public class MyThread extends Thread { @Override public void run() { try { //消耗一下时间, for(int i=0; i<10000; i++) { System.out.println(i); } System.out.println("线程执行"); Thread.sleep(10000); System.out.println("线程执行完成"); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println("进入Catch"); e.printStackTrace(); } //休眠10秒 } }
测试类:
package com.feng.example; public class ThreadTest { /** * @param args */ public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); thread.interrupt(); System.out.println("end"); } }
运行结果:
9997 9998 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.feng.example.MyThread.run(MyThread.java:15) 9999 线程执行 进入Catch
因而可知:先sleep再interrupt会直接抛出异常,若是先interrupt,再进入sleep,在sleep时才会抛出异常