一、线程的状态

1.线程状态:

  1. 新建:当线程被创建的时候,会短暂处于这种状态。此时已经分配了系统资源,并执行了初始化。
  2. 就绪:在这种状态下,只要调度器把cpu时间片分给线程就可以执行
  3. 阻塞;线程可以运行,但摸个条件阻止它的运行。此时调度器将忽略线程,直到线程进入就绪状态才又可能执行操作
  4. 死亡:处于死亡或终止状态的线程将不再是可以调度的,它的任务以结束,或不再是可运行的

二、线程进入阻塞的原因:

1.休眠时阻塞

  1. class SleepBlock implements Runnable{
  2. @Override
  3. public void run() {
  4. try {
  5. TimeUnit.SECONDS.sleep(100);
  6. } catch (InterruptedException e) {
  7. System.out.println("InterruptedException");
  8. }
  9. System.out.println("Exiting SleepBlock run()");
  10. }
  11. }

2.等待阻塞

通过wait()将线程挂起,直到线程得到了notify()或notifyAll()消息(或者是concurrent类库中等价的signal或signalAll),线程才会进入就绪状态

  1. public synchronized void waxed() {//打蜡
  2. waxOn = true;
  3. notifyAll();
  4. }
  5. public synchronized void waitForWaxing() throws InterruptedException {
  6. while (waxOn == false)
  7. wait();
  8. }

3.I/O阻塞

等待某个输出/输入完成

  1. //3.输入输出导致堵塞
  2. class IOBlock implements Runnable{
  3. private InputStream in;
  4. IOBlock(InputStream in){
  5. this.in=in;
  6. }
  7. @Override
  8. public void run() {
  9. try {
  10. System.out.println("等待输入");
  11. in.read();
  12. } catch (IOException e) {
  13. if (Thread.currentThread().isInterrupted()){
  14. System.out.println("Interrupted from block I/O");
  15. }else{
  16. throw new RuntimeException(e);
  17. }
  18. }
  19. System.out.println("Exiting I/OBlock run()");
  20. }
  21. }

4.互斥时阻塞

任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁。

  1. class SynchroizedBlocked implements Runnable{
  2. public synchronized void f(){
  3. while (true){
  4. Thread.yiled();//程序将再次阻塞
  5. }
  6. public void run(){
  7. System.out.println("等待任务执行");
  8. f();//在f()循环的时候阻塞
  9. System.out.println("任务执行结束");
  10. }
  11. }

扩展:

1.可以通过jps命令来查看阻塞的程序,通过jstack来查程序中阻塞的线程
image.png
2.也可以通过jconsole来调用java后台监视系统:
image.png

三、 中断:

有时候我们希望中断被阻塞的线程

1.中断线程的方式:

  1. Thread类中包含interrupt()方法,可以终止被阻塞的任务,被终止的任务将将抛出InterruptedException异常
  2. Executor中调用showdowNow(),它将发送一个Interrupt()调用给它启动的所以线程。从而引发打断异常
  3. cancel()方法:是一种用来中断由Exceutor启动的单个线程的方式。Exceutor中的submit来创建线程,通过返回一个泛型的Future<?>,来调用cancel方法,来终止某个特定的任务。如果将true传统给该方法,那他就会拥有在该线程上调用interrupt()已停止这个线程的权限。

2.终止因休眠阻塞的线程:

  1. /1.sleep导致阻塞
  2. class SleepBlock implements Runnable{
  3. @Override
  4. public void run() {
  5. try {
  6. TimeUnit.SECONDS.sleep(100);
  7. } catch (InterruptedException e) {
  8. System.out.println("InterruptedException");
  9. }
  10. System.out.println("Exiting SleepBlock run()");
  11. }
  12. }
  13. public class Interrupting {
  14. private static ExecutorService executor = Executors.newCachedThreadPool();
  15. static void test(Runnable r) throws InterruptedException {
  16. Future<?> f = executor.submit(r);
  17. TimeUnit.MILLISECONDS.sleep(100);
  18. System.out.println("Interrupting "+r.getClass().getName());
  19. f.cancel(true);//中断任务
  20. System.out.println("Interrupting sent to"+r.getClass().getName());
  21. }
  22. //jstack
  23. public static void main(String[] args) throws InterruptedException {
  24. test(new SleepBlock());//定时阻塞
  25. TimeUnit.SECONDS.sleep(50);
  26. System.out.println("系统关闭");
  27. System.exit(0);
  28. }
  29. }

3.中断I/O导致的阻塞(io阻塞不能中断)

  1. class IOBlock implements Runnable{
  2. private InputStream in;
  3. IOBlock(InputStream in){
  4. this.in=in;
  5. }
  6. @Override
  7. public void run() {
  8. try {
  9. System.out.println("等待输入");
  10. in.read();
  11. } catch (IOException e) {
  12. if (Thread.currentThread().isInterrupted()){
  13. System.out.println("Interrupted from block I/O");
  14. }else{
  15. throw new RuntimeException(e);
  16. }
  17. }
  18. System.out.println("Exiting I/OBlock run()");
  19. }
  20. }
  21. public class Interrupting {
  22. private static ExecutorService executor = Executors.newCachedThreadPool();
  23. static void test(Runnable r) throws InterruptedException {
  24. Future<?> f = executor.submit(r);
  25. TimeUnit.MILLISECONDS.sleep(100);
  26. System.out.println("Interrupting "+r.getClass().getName());
  27. f.cancel(true);//中断任务
  28. System.out.println("Interrupting sent to"+r.getClass().getName());
  29. }
  30. public static void main(String[] args) throws InterruptedException {
  31. test(new IOBlock(System.in));//输入输出阻塞
  32. TimeUnit.SECONDS.sleep(10);
  33. System.out.println("系统关闭");
  34. System.exit(0);
  35. }
  36. }

我们发现,通过调用Future类中的cancel方法并不能中断IO,所以对于IO的阻塞去关闭底层的数据源:

  1. public class CloseResource {
  2. public static void main(String[] args) throws IOException, InterruptedException {
  3. ExecutorService service = Executors.newCachedThreadPool();
  4. ServerSocket serverSocket = new ServerSocket(8080);
  5. InputStream inputStream = new Socket("localhost",8080).getInputStream();
  6. service.execute(new IOBlock(inputStream));
  7. service.execute(new IOBlock(System.in));
  8. TimeUnit.MILLISECONDS.sleep(200);
  9. System.out.println("Shutting down all thread");
  10. service.shutdownNow();只能引发打断异常
  11. //关闭底层资源
  12. TimeUnit.SECONDS.sleep(1);
  13. System.out.println("Cloas"+inputStream.getClass().getName());
  14. inputStream.close();//只能中断Socket
  15. TimeUnit.SECONDS.sleep(1);
  16. System.out.println("Cloas"+System.in.getClass().getName());
  17. System.in.close();//1.8以后不中断InputStream
  18. }
  19. }


4.中断由SynchroizedBlocked锁导致的阻塞:

示列一:

  1. class SynchroizedBlocked implements Runnable{
  2. public synchronized void f(){
  3. while (true)
  4. Thread.yield();//有一个任务已经获得锁则其他任务进不来,该任务则一直在运行,从而造成阻塞
  5. }
  6. public SynchroizedBlocked(){
  7. new Thread(){
  8. @Override
  9. public void run() {
  10. f();
  11. System.out.println("其他业务逻辑代码");
  12. }
  13. }.start();
  14. }
  15. @Override
  16. public void run() {
  17. System.out.println("Trying to call f()");
  18. f();
  19. System.out.println("Exiting synchoizedBlock.run()");
  20. }
  21. }
  22. public class Interrupting {
  23. private static ExecutorService executor = Executors.newCachedThreadPool();
  24. static void test(Runnable r) throws InterruptedException {
  25. Future<?> f = executor.submit(r);
  26. TimeUnit.MILLISECONDS.sleep(100);
  27. System.out.println("Interrupting "+r.getClass().getName());
  28. f.cancel(true);//中断任务
  29. System.out.println("Interrupting sent to"+r.getClass().getName());
  30. }
  31. public static void main(String[] args) throws InterruptedException {
  32. TimeUnit.SECONDS.sleep(10);
  33. System.out.println("系统关闭");
  34. System.exit(0);
  35. }
  36. }

示列二:
当被锁的任务为死循环时:

  1. class SynchroizedBlocked implements Runnable{
  2. private volatile AtomicInteger count=new AtomicInteger();
  3. private volatile boolean falg=false;
  4. public synchronized void f(){
  5. while (!falg){
  6. int i = count.addAndGet(2);
  7. if (i==50)
  8. falg=true;
  9. }
  10. }

当循环次数超过设定的次数时候,原子性操作的Boolean将变为true从而跳出循环。
注意:我们去不能去终止正在试图获取Synchronized锁或者试图执行I/O操作的线程。

示列三:一个同一个互斥被同一个任务多次获得

  1. package com.package21.multilock;
  2. public class MultiLock {
  3. public synchronized void f1(int count){
  4. if (count-->0){
  5. System.out.println("f1() and f2() "+count);
  6. f2(count);
  7. }
  8. }
  9. public synchronized void f2(int count){
  10. if (count-->0){
  11. System.out.println("f2() and f1() "+count);
  12. f1(count);
  13. }
  14. }
  15. public static void main(String[] args) {
  16. MultiLock multiLock = new MultiLock();
  17. new Thread (){
  18. @Override
  19. public void run() {
  20. multiLock.f1(10);
  21. }
  22. }.start();
  23. }
  24. }

5.ReentranLock中断阻塞:

无论何时,只要任务不可中断式被阻塞,都有潜在锁住程序的可能,而ReentranLock上阻塞的任务具备可以被中断的能力。

  1. public class BlockedMutex {
  2. private Lock lock = new ReentrantLock();
  3. public BlockedMutex() {
  4. lock.lock();//加锁
  5. }
  6. public void f() {
  7. try {
  8. lock.lockInterruptibly();//如果当前线程未被中断则获得锁,如果当前线程被中断则出现异常。
  9. System.out.println("lock f()");
  10. } catch (InterruptedException e) {
  11. System.out.println("Interrupted form lpck in f()");
  12. }
  13. }
  14. }
  15. class BlockedMutex_Two implements Runnable {
  16. BlockedMutex blockedMutex = new BlockedMutex();
  17. @Override
  18. public void run() {
  19. System.out.println("waiting for f() in BlockedMutex");
  20. blockedMutex.f();
  21. System.out.println("Broken out of blocked call");
  22. }
  23. }
  24. class Interrupting2 {
  25. public static void main(String[] args) throws InterruptedException {
  26. Thread thread = new Thread(new BlockedMutex_Two());
  27. thread.start();
  28. TimeUnit.SECONDS.sleep(1);
  29. System.out.println("Issuing t.interrupt()");
  30. thread.interrupt();
  31. }
  32. }

四、检查中断:

1. 通过interrupted()方法来检查线程是否中断

  1. //标识类
  2. class NeedsCleanup {
  3. private final int id;
  4. public NeedsCleanup(int ident) {
  5. id = ident;
  6. System.out.println("NeedsCleanup " + id);
  7. }
  8. public void cleanup() {
  9. System.out.println("Cleaning up " + id);
  10. }
  11. }
  12. class Blocked3 implements Runnable {
  13. private volatile double d = 0.0;
  14. public void run() {
  15. try {
  16. while (!Thread.interrupted()) {//检查线程是否中断
  17. NeedsCleanup n1 = new NeedsCleanup(1);
  18. try {
  19. System.out.println("Sleeping");
  20. TimeUnit.SECONDS.sleep(2);
  21. NeedsCleanup n2 = new NeedsCleanup(2);
  22. try {
  23. System.out.println("Calculating");
  24. for (int i = 1; i < 2500000; i++)
  25. d = d + (Math.PI + Math.E) / d;
  26. System.out.println("Finished time-consuming operation");
  27. } finally {
  28. n2.cleanup();
  29. }
  30. }
  31. finally {
  32. n1.cleanup();
  33. }
  34. }
  35. System.out.println("Exiting via while() test");
  36. } catch (InterruptedException e) {
  37. System.out.println("Exiting via InterruptedException");
  38. }
  39. }
  40. }
  41. public class InterruptingIdiom {
  42. public static void main(String[] args) throws Exception {
  43. Thread t = new Thread(new Blocked3());
  44. t.start();
  45. TimeUnit.MILLISECONDS.sleep(2010);
  46. t.interrupt();
  47. }
  48. }

注意:所有可能中断需要被清理的对象创建操作的后面。都必须紧跟Try-finally子句,从而使无论run循环如何退出,清理都会发生。