线程停止与volatile
1.使用标志位停止线程
在Java中希望停止线程,可以使用设置标志位的方法,如下例所示:
class SimpleTask implements Runnable{
private boolean stop = false;
public void stop(){
stop = true;
}
@Override
public void run() {
while(!stop){
}
System.out.println("quit");
}
}
public class StopThreadTest {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
SimpleTask simpleTask = new SimpleTask();
executor.execute(simpleTask);
executor.shutdown();
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String word = sc.next();
if(word.equals("stop")){
System.out.println("stop the task");
simpleTask.stop();
}else if(word.equals("!"))
break;
}
}
}
然而无法成功停止线程。原因,没有同步,就不能保证后台线程何时“看到”main线程堆stop的值所做的改编。虚拟机将
while(!stop){}
//转化为
if(!stop)
while(true){}
改进,使用同步方法访问stop域。注意:读(getStop)写(stop)方法都要同步。
class SimpleTask implements Runnable{
private boolean stop = false;
public synchronized void stop(){
stop = true;
}
public synchronized boolean getStop(){
return stop;
}
@Override
public void run() {
while(!getStop()){
}
System.out.println("quit");
}
}
public class StopThreadTest {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
SimpleTask simpleTask = new SimpleTask();
executor.execute(simpleTask);
executor.shutdown();
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String word = sc.next();
if(word.equals("stop")){
System.out.println("stop the task");
simpleTask.stop();
}else if(word.equals("!"))
break;
}
}
}
使用volatile关键字可以获得一个更简洁、性能更好的版本
class SimpleTask implements Runnable{
private volatile boolean stop = false;
public void stop(){
stop = true;
}
@Override
public void run() {
while(!stop){
}
System.out.println("quit");
}
}
public class StopThreadTest {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
SimpleTask simpleTask = new SimpleTask();
executor.execute(simpleTask);
executor.shutdown();
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String word = sc.next();
if(word.equals("stop")){
System.out.println("stop the task");
simpleTask.stop();
}else if(word.equals("!"))
break;
}
}
}
原因:虽然volatile不执行互斥访问,但它可以保证任何一个线程(比如本例中的main线程)读取该域(stop)的时候都能看到最近刚刚被写入的值。
结论:
- 当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步(
synchronized)。如果没有同步,就无法保证一个线程所做的修改可以被另一个线程获知。 - 如果需要线程之间的交互通信,而不需要互斥,
volatile修饰符就是一种可以接收的同步形式。
参考:
Effective Java
2.使用线程的interrupt方法停止线程
原始链接:How can I kill a thread? without using stop();
public class HelloWorld {
public static void main(String[] args) throws Exception {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(5000);
System.out.println("Hello World!");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread.start();
System.out.println("press enter to quit");
System.in.read();
thread.interrupt();
}
}
使用这种方法停止线程的好处:Interrupting 可以让sleep()与wait()的线程直接被抛出异常,然后被终止。而不用等待其sleep完才能终止。
但也有不少人对这种方法提出质疑,认为这样终止线程比较危险。
总的来说使用第1种方法比较保守、安全。
线程停止与volatile的更多相关文章
- java线程学习之volatile关键字
volatile变量的主要作用:是使变量在多个线程间可见. 在java中每一个线程都会有一块工作内存区,其中存放着所有线程共享的主内存的变量值的拷贝.当线程执行时,它在自己的工作内存区操作这些变量,为 ...
- 注意!你的Thread.Abort方法真的让线程停止了吗?
大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...
- C# Thread.Abort方法真的让线程停止了吗?
大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...
- Java如何检查一个线程停止或没有?
Java如何检查一个线程停止或没有? 解决方法 下面的示例演示如何使用 isAlive()方法检查一个线程是否停止. public class Main { public static void ma ...
- EF Core使用SQL调用返回其他类型的查询 ASP.NET Core 2.0 使用NLog实现日志记录 CSS 3D transforms cSharp:use Activator.CreateInstance with an Interface? SqlHelper DBHelper C# Thread.Abort方法真的让线程停止了吗? 注意!你的Thread.Abort方法真
EF Core使用SQL调用返回其他类型的查询 假设你想要 SQL 本身编写,而不使用 LINQ. 需要运行 SQL 查询中返回实体对象之外的内容. 在 EF Core 中,执行该操作的另一种方法 ...
- (一)juc线程高级特性——volatile / CAS算法 / ConcurrentHashMap
1. volatile 关键字与内存可见性 原文地址: https://www.cnblogs.com/zjfjava/category/979088.html 内存可见性(Memory Visibi ...
- Java线程停止interrupt()方法
程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误.在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程. 中 ...
- Thread的中断机制(interrupt),循环线程停止的方法
一.中断原理 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个 ...
- java多线线程停止正确方法
//军队线程 //模拟作战双方的行为 public class ArmyRunnable implements Runnable { //volatile保证了线程可以正确的读取其他线程写入的值 // ...
随机推荐
- 项目管理器 ProjectManager Beta 10 发布
本次更新内容: 可以设置主界面是否显示表格线 去除了开发日志界面的表格线,看起来好像好看一些 修复主界面时间显示的问题 自定义问候语 修复习惯统计记录时间显示错误的问题 修复创建项目时间错误问题 增加 ...
- 消息中间件选型分析——从Kafka与RabbitMQ的对比来看全局
一.前言 消息队列中间件(简称消息中间件)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成.通过提供消息传递和消息排队模型,它可以在分布式环境下提供应用解耦 ...
- SQL类型注入
前言: 继续进行未完成的sql注入学习 今天学习了各类型注入.前来进行总结. 目录: 数字型注入 字符型注入 提交注注入 GET注入 POST注入 COOKIE注入 正文: 数字型注入:www.xxx ...
- TCP/IP学习笔记(二):TCP连接的建立与终止
TCP连接的三次握手: (1)请求短发送一个SYN段指明客户打算连接的服务器的端口,以及初始序号ISN(1415535521),报文段中SYN=1:TCP规定:SYN报文段不能携带数据,但是要消耗一个 ...
- Spring-framework 源码导入 IntelliJ IDEA 记录
前言 想学习spring框架,不看源码怎么行.网上有很多教程,但是自己实施起来还是稍微有点坎坷的,不过最后还是成功了.遂以此文记录. 环境说明: Idea 2017.2.5 spring-frame ...
- [LeetCode] Distribute Candies 分糖果
Given an integer array with even length, where different numbers in this array represent different k ...
- [Codeforces 448C]Painting Fence
Description Bizon the Champion isn't just attentive, he also is very hardworking. Bizon the Champion ...
- ●POJ 2828 Buy Tickets
题链: http://poj.org/problem?id=2828 题解: 线段树. 逆向考虑这个过程.最后的序列S共有n个元素. 先看最后一个人,如果他插入到第i位,那么他最终的位置就是当前序列S ...
- [Noi2013]书法家
来自FallDream的博客,未经允许,请勿转载,谢谢. 小E同学非常喜欢书法,他听说NOI2013已经开始了,想题一幅“NOI”的字送给大家. 小E有一张非常神奇的纸,纸可以用一个n 行m 列的二维 ...
- 分区工具PQ
http://www.disktool.cn/jiaocheng/resize-partition.html