终止线程

Java中原来在Thread中提供了stop()方法来终止线程,但这个方法是不安全的,所以一般不建议使用。

本文向大家介绍使用interrupt方法中断线程。

使用interrupt方法来终端线程可分为两种情况:

  • (1)线程处于阻塞状态,如使用了sleep方法。
  • (2)使用while(!isInterrupted()){……}来判断线程是否被中断。

在第一种情况下使用interrupt方法,sleep方法将抛出一个InterruptedException例外,而在第二种情况下线程将直接退出。下面的代码演示了在第一种情况下使用interrupt方法。

public class ThreadInterrupt extends Thread
{ public void run() { try { sleep(50000);  // 延迟50秒 } catch (InterruptedException e) { System.out.println(e.getMessage()); } } public static void main(String[] args) throws Exception { Thread thread = new ThreadInterrupt(); thread.start(); System.out.println("在50秒之内按任意键中断线程!"); System.in.read(); thread.interrupt(); thread.join(); System.out.println("线程已经退出!"); }
}

以上代码运行输出结果为:

在50秒之内按任意键中断线程!sleep interrupted
线程已经退出!

生产者/消费者问题

生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况:

存储空间已满,而生产者占用着它,消费者等着生产者让出空间从而去除产品,生产者等着消费者消费产品,从而向空间中添加产品。互相等待,从而发生死锁。

以下实例演示了如何通过线程解决生产者/消费者问题:

public class ProducerConsumerTest {public static void main(String[] args) {CubbyHole c = new CubbyHole();Producer p1 = new Producer(c, 1);Consumer c1 = new Consumer(c, 1);p1.start(); c1.start();}
}
class CubbyHole {private int contents;private boolean available = false;public synchronized int get() {while (available == false) {try {wait();}catch (InterruptedException e) {}}available = false;notifyAll();return contents;}public synchronized void put(int value) {while (available == true) {try {wait();}catch (InterruptedException e) { } }contents = value;available = true;notifyAll();}
}class Consumer extends Thread {private CubbyHole cubbyhole;private int number;public Consumer(CubbyHole c, int number) {cubbyhole = c;this.number = number;}public void run() {int value = 0;for (int i = 0; i < 10; i++) {value = cubbyhole.get();System.out.println("消费者 #" + this.number+ " got: " + value);}}
}class Producer extends Thread {private CubbyHole cubbyhole;private int number;public Producer(CubbyHole c, int number) {cubbyhole = c;this.number = number;}public void run() {for (int i = 0; i < 10; i++) {cubbyhole.put(i);System.out.println("生产者 #" + this.number + " put: " + i);try {sleep((int)(Math.random() * 100));} catch (InterruptedException e) { }}}
}

以上代码运行输出结果为:

消费者 #1 got: 0
生产者 #1 put: 0
生产者 #1 put: 1
消费者 #1 got: 1
生产者 #1 put: 2
消费者 #1 got: 2
生产者 #1 put: 3
消费者 #1 got: 3
生产者 #1 put: 4
消费者 #1 got: 4
生产者 #1 put: 5
消费者 #1 got: 5
生产者 #1 put: 6
消费者 #1 got: 6
生产者 #1 put: 7
消费者 #1 got: 7
生产者 #1 put: 8
消费者 #1 got: 8
生产者 #1 put: 9
消费者 #1 got: 9

获取线程状态

Java 线程的生命周期中,在 Thread 类里有一个枚举类型 State,定义了线程的几种状态,分别有:

  • New
  • Runnable
  • Blocked
  • Waiting
  • Timed Waiting
  • Terminated

各个状态说明:

1. 初始状态 - NEW

声明:

public static final Thread.State NEW

实现 Runnable 接口和继承 Thread 可以得到一个线程类,new 一个实例出来,线程就进入了初始状态。

2. RUNNABLE

声明:

public static final Thread.State RUNNABLE

2.1. 就绪状态

就绪状态只是说你资格运行,调度程序没有挑选到你,你就永远是就绪状态。

调用线程的 start() 方法,此线程进入就绪状态。

当前线程 sleep() 方法结束,其他线程 join() 结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。

当前线程时间片用完了,调用当前线程的 yield() 方法,当前线程进入就绪状态。

锁池里的线程拿到对象锁后,进入就绪状态。

2.2. 运行中状态

线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。

3. 阻塞状态 - BLOCKED

声明:

public static final Thread.State BLOCKED

阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。

4. 等待 - WAITING

声明:

public static final Thread.State WAITING

处于这种状态的线程不会被分配 CPU 执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。

5. 超时等待 - TIMED_WAITING

声明:

public static final Thread.State TIMED_WAITING

处于这种状态的线程不会被分配 CPU 执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。

6. 终止状态 - TERMINATED

声明:

public static final Thread.State TERMINATED

当线程的 run() 方法完成时,或者主线程的 main() 方法完成时,我们就认为它终止了。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。

在一个终止的线程上调用 start() 方法,会抛出 java.lang.IllegalThreadStateException 异常。

以下实例演示了如何获取线程的状态:

class thread implements Runnable
{ public void run() { //  thread2  - 超时等待try{ Thread.sleep(1500); }  catch (InterruptedException e)  { e.printStackTrace(); } System.out.println("State of thread1 while it called join() method on thread2 -"+ Test.thread1.getState()); try{ Thread.sleep(200); }  catch (InterruptedException e)  { e.printStackTrace(); }      }
} public class Test implements Runnable
{ public static Thread thread1; public static Test obj; public static void main(String[] args) { obj = new Test(); thread1 = new Thread(obj); // 创建 thread1,现在是初始状态System.out.println("State of thread1 after creating it - " + thread1.getState()); thread1.start(); // thread1 - 就绪状态System.out.println("State of thread1 after calling .start() method on it - " +  thread1.getState()); } public void run() { thread myThread = new thread(); Thread thread2 = new Thread(myThread); // 创建 thread1,现在是初始状态System.out.println("State of thread2 after creating it - "+ thread2.getState()); thread2.start(); // thread2 - 就绪状态System.out.println("State of thread2 after calling .start() method on it - " +  thread2.getState()); // moving thread1 to timed waiting state try{ //moving - 超时等待Thread.sleep(200); }  catch (InterruptedException e)  { e.printStackTrace(); } System.out.println("State of thread2 after calling .sleep() method on it - "+  thread2.getState() ); try { // 等待 thread2 终止thread2.join(); }  catch (InterruptedException e)  { e.printStackTrace(); } System.out.println("State of thread2 when it has finished it's execution - " +  thread2.getState()); } }

以上代码运行输出结果为:

State of thread1 after creating it - NEW
State of thread1 after calling .start() method on it - RUNNABLE
State of thread2 after creating it - NEW
State of thread2 after calling .start() method on it - RUNNABLE
State of thread2 after calling .sleep() method on it - TIMED_WAITING
State of thread1 while it called join() method on thread2 -WAITING
State of thread2 when it has finished it's execution - TERMINATED

获取所有线程

以下实例演示了如何使用 getName() 方法获取所有正在运行的线程:

public class Main extends Thread {public static void main(String[] args) {Main t1 = new Main();t1.setName("thread1");t1.start();ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();int noThreads = currentGroup.activeCount();Thread[] lstThreads = new Thread[noThreads];currentGroup.enumerate(lstThreads);for (int i = 0; i < noThreads; i++)System.out.println("线程号:" + i + " = " + lstThreads[i].getName());}
}

以上代码运行输出结果为:

线程号:0 = main
线程号:1 = thread1

查看线程优先级

以下实例演示了如何使用 getThreadId() 方法获取线程id:

public class Main extends Object {private static Runnable makeRunnable() {Runnable r = new Runnable() {public void run() {for (int i = 0; i < 5; i++) {Thread t = Thread.currentThread();System.out.println("in run() - priority="+ t.getPriority()+ ", name=" + t.getName());try {Thread.sleep(2000);}catch (InterruptedException x) {}}}};return r;}public static void main(String[] args) {System.out.println("in main() - Thread.currentThread().getPriority()=" + Thread.currentThread().getPriority());System.out.println("in main() - Thread.currentThread().getName()="+ Thread.currentThread().getName());Thread threadA = new Thread(makeRunnable(), "threadA");threadA.start();try {Thread.sleep(3000);}catch (InterruptedException x) {}System.out.println("in main() - threadA.getPriority()="+ threadA.getPriority());}
}

以上代码运行输出结果为:

in main() - Thread.currentThread().getPriority()=5
in main() - Thread.currentThread().getName()=main
in run() - priority=5, name=threadA
in run() - priority=5, name=threadA
in main() - threadA.getPriority()=5
in run() - priority=5, name=threadA
in run() - priority=5, name=threadA
in run() - priority=5, name=threadA

中断线程

以下实例演示了如何使用interrupt()方法来中断线程并使用 isInterrupted() 方法来判断线程是否已中断:

public class Main extends Object
implements Runnable {public void run() {try {System.out.println("in run() - 将运行 work2() 方法");work2();System.out.println("in run() - 从 work2() 方法回来");}catch (InterruptedException x) {System.out.println("in run() - 中断 work2() 方法");return;}System.out.println("in run() - 休眠后执行");System.out.println("in run() - 正常离开");}public void work2() throws InterruptedException {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("C isInterrupted()=" + Thread.currentThread().isInterrupted());Thread.sleep(2000);System.out.println("D isInterrupted()=" + Thread.currentThread().isInterrupted());}}}public void work() throws InterruptedException {while (true) {for (int i = 0; i < 100000; i++) {int j = i * 2;}System.out.println("A isInterrupted()=" + Thread.currentThread().isInterrupted());if (Thread.interrupted()) {System.out.println("B isInterrupted()=" + Thread.currentThread().isInterrupted());throw new InterruptedException();}}}public static void main(String[] args) {Main si = new Main();Thread t = new Thread(si);t.start();try {Thread.sleep(2000);}catch (InterruptedException x) {}System.out.println("in main() - 中断其他线程");t.interrupt();System.out.println("in main() - 离开");}
}

以上代码运行输出结果为:

in run() - 将运行 work2() 方法
in main() - 中断其他线程
in main() - 离开
C isInterrupted()=true
in run() - 中断 work2() 方法

Java 线程实例二(终止线程、生产者/消费者问题、获取线程状态、获取所有线程、查看线程优先级、中断线程)相关推荐

  1. 菜鸟学习笔记:Java提升篇8(线程2——线程的基本信息、线程安全、死锁、生产者消费者模式、任务调度)

    菜鸟学习笔记:Java提升篇8(线程2--线程的基本信息.线程安全.死锁.生产者消费者模式.任务调度) 线程的基本信息 线程同步 线程安全 死锁 生产者消费者模式 任务调度(了解) 线程的基本信息 J ...

  2. 7.生产者消费者 案例 (使用Lock 同步锁 方式,使用Condition完成线程之间的通信)...

    1 /* 2 * 生产者消费者 案例 (使用Lock 同步锁 方式,使用Condition完成线程之间的通信) 3 * */ 4 public class TestProductorAndConsum ...

  3. java 读者写者_Java实现生产者消费者问题与读者写者问题详解

    1.生产者消费者问题 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品.解决生产者/消费者问题的方法可分为两 ...

  4. Java 多线程(二)线程间的通信应用--生产者消费者(未完)

    对于多个生产者和消费者. 为什么要定义while判断标记. 原因:让被唤醒的线程再一次判断标记. 为什么定义notifyAll, 因为需要唤醒对方线程. 因为只用notify,容易出现只唤醒本方线程的 ...

  5. Java20-day11【实现多线程(进程、线程-调度-控制-生命周期)、线程同步(同步代码块、线程安全、Lock)、生产者消费者(模式概述、案例)】

    视频+资料[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg   提取码:zjxs] Java基础--学习笔记(零起点打开java世界的大门)--博 ...

  6. 线程的基本协作和生产者消费者

    协作基础(wait/notify) Java的根父类是Object,Java在Object类而非Thread类中,定义了一些线程协作的基本方法,使得每个对象都可以调用这些方法,这些方法有两类,一类是w ...

  7. Python多线程篇一,theanding库、queue队列、生产者消费者模式爬虫实战代码超详细的注释、自动分配线程对应多任务,GIF演示【傻瓜式教程】

    ⭐ 简介:大家好,我是zy阿二,我是一名对知识充满渴望的自由职业者. ☘️ 最近我沉溺于Python的学习中.你所看到的是我的学习笔记. ❤️ 如果对你有帮助,请关注我,让我们共同进步.有不足之处请留 ...

  8. java中synchronized同步锁实现生产者消费者模式

    synchronized介绍 一.基本概念 synchronized关键字是java里面用来在多线程环境下保证线程安全的同步锁:java里面有对象锁和类锁,对象锁是用在对象实例的方法上或者一个对象实例 ...

  9. java多线程并发之旅-09-java 生产者消费者 Producer/Consumer 模式

    生产者消费者模式 在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类.函数.线程.进程等).产生数据的模块,就形象地称为生产 ...

最新文章

  1. Linux centos6.5 64下oracle10g_静默安装完整版
  2. react hook——你可能不是“我”所认识的useEffect
  3. 使用Signature Tool自动生成P/Invoke调用Windows API的C#函数声明
  4. Python使用远程仓库时建议忽略的文件
  5. python codefirst_Python code.co_consts方法代码示例
  6. c+智能指针源码分析_C ++中的智能指针
  7. 2017年最受欢迎的10个编程挑战网站,值得收藏!
  8. 转:Apple的App Analytics统计平台你必须知道的
  9. take android,Protake
  10. 各种版本操作系统的虚拟机镜像文件
  11. 旧手机利用(Android),当wifi,当mic,当ipcamera
  12. Shell 进阶指南
  13. 360怎么修改域名服务器地址,怎样修改DNS地址
  14. 然后查看服务器运行情况,netstat命令查看服务器运行情况
  15. 上顿号符号_标点符号的用法一一顿号
  16. 深圳小众爬山点推荐 人少景美周末必备
  17. 什么是超级电容?它与普通电容有何区别?
  18. 基于SSM的网红书购物商城(源码+论文+开题报告+答辩PPT)
  19. 雷军20年前作文:我会当一辈子程序员 + 分享雷军22年前写的代码
  20. 数美科技 | 黄牛也武装到牙齿,航司怎么样打赢这场无形战争?

热门文章

  1. 精选| 2020年12月R新包推荐(第49期)
  2. Retouch Pro for Mac(ps图像修饰插件)支持ps 2021
  3. NOIP2002复赛 普及组 第1题
  4. 第16课 开灯关灯 《小学生C++趣味编程》
  5. 【ES9(2018)】RegExp扩展
  6. python使用技巧_python小技巧
  7. Qt工作笔记-正则表达式QProcess::startDetached中正则表达式的使用
  8. QML工作笔记-2种输入框的使用(TextField与TextInput)
  9. Qt文档阅读笔记-The Meta-Object System解析及实例
  10. Qt工作笔记-主界面往模式对话框emit信号,有注意的问题