Thread.stop()方法
- 此方法虽然可以立即停止线程,但是是不安全的方法。已被废弃。
- 如果强制使用此方法停止线程,可能会使一些清理工作得不到完成。另外一个情况就是对锁的对象进行了解锁,导致数据得不到同步的问题。
interrupt()方法
- 调用此方法会在当前线程中打一个停止的标记,并不会真正的停止线程。
- 要想真正的停止线程,还需要结合
interrupted()
或isInterrupted()
interrupted | interrupted
- interrupted: 测试
当前
线程是否处已经中断 - isInterrupted: 测试线程是否处已经中断
interrupted的方法声明
publc static boolean interrupted();
isInterrupted的方法声明
publc boolean isInterrupted();
两者的区别
- interrupted:判断的是当前线程 this.interrupted()
- isInterrupted: 判断的是调用此方法的线程
- interrupt() 方法执行后,调用interrupted() | isInterrupted() ,会打印为
true
(默认为false)。
false代表线程未中断,true为线程中断。而interrupted()方法具有清除状态的功能,所以如果第二次调用 interrupted() 方法会返回false;
异常法终止线程
即使用interrupted
或isInterrupted
进行判断,满足条件就抛出异常
class MyThread implements Runnable {
@Override
public void run() {
try {
for (int i=0;i<100;i++){
if (Thread.currentThread().interrupted()){
System.out.println("线程要被终止");
throw new InterruptedException();
}
System.out.println(i);
}
System.out.println("-----"+ "线程终止后我将不再执行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("线程终止了");
}
}
}
在睡眠中终止线程
如下代码
class Interrupt implements Runnable {
@Override
public void run() {
int sun = 0;
try {
while (!Thread.currentThread().isInterrupted() && sun < 10000) {
if (sun % 100 == 0) {
System.out.println(sun);
}
sun++;
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("------------+++++");
}
@Test
public void demo01() throws InterruptedException {
Runnable runnable = new Interrupt();
Thread thread = new Thread(runnable);
thread.start();
thread.sleep(1000);
thread.interrupt();
}
在sleep状态下停止线程,会直接进入clatch语句,并且清除中断状态值,使之变成false
当线程处于wait()时,执行 interrupt() 也会抛出InterruptedException异常。此时无需判断Thread.currentThread().isInterrupted()
return方法终止线程
class s implements Runnable{
@Override
public void run() {
while (Thread.currentThread().isInterrupted()){
System.out.println("-----"+ "线程终止后我将不再执行");
return;
}
}
}
此方法不推荐使用,建议还是使用异常法,可以在catch块中进行相关的处理
私有堆栈与公有堆栈
线程的私有堆栈与公有堆栈,私有堆栈与公有堆栈中的数值是不同步的
如下代码
class PrintString implements Runnable{
private boolean iscont = true;
public boolean isIscont() {
return iscont;
}
public void setIscont(boolean iscont) {
this.iscont = iscont;
}
@Override
public void run() {
System.out.println("进入到了run ···");
while (iscont){
System.out.println("---");
}
System.out.println("线程被终止了");
}
}
class Run{
public static void main(String[] args) {
try {
PrintString printString = new PrintString();
Thread thread = new Thread(printString);
thread.start();
thread.sleep(1000);
printString.setIscont(false);
System.out.println("已经赋值为false");
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在JVM配置成Server的环境下执行此代码线程并不能停止,原因便是 私有堆栈与公有堆栈中的数值是不同步的。线程一直在私有堆栈中提取 boolean iscont = true; 而 printString.setIscont(false);更新的使公有堆中的数据。所以线程还是会处于死循环中。
volatile
volatile : 关键字的主要作用是使变量在多个线程间可见
使用此特性便可以进行线程的中断
中断线程
class PrintString implements Runnable{
//此变量的类型
private volatile boolean iscont = true;
public boolean isIscont() {
return iscont;
}
public void setIscont(boolean iscont) {
this.iscont = iscont;
}
@Override
public void run() {
System.out.println("进入到了run ···");
while (iscont){
System.out.println("---");
}
System.out.println("线程被终止了");
}
}
使用此关键字,便可强制线程从公有堆中获取数据
弊端
在线程处于阻塞状态时,此方法便不能够中断线程。
如下代码,生产者进行生产,消费者消费,生产的速度大于消费的速度。若满足生产的数量,则进入阻塞。
class VolatileProducers implements Runnable{
//BlockingQueue 即阻塞队列
BlockingQueue blockingQueue ;
public static volatile boolean cancel = false;
Volatileroduction volatileroduction = new Volatileroduction();
/** 构造方法*/
public VolatileProducers(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
/** 调用过程未出现阻塞状态的方法 可以正常进行中断操作*/
//volatileroduction.VolatileProducers1(cancel);
/** 会产生处于阻塞状态*/
volatileroduction.VolatileProducers2(cancel,blockingQueue);
/** 使用interputed中断线程*/
//volatileroduction.VolatileProducers3(cancel,blockingQueue);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("--"+cancel);
System.out.println("--"+Thread.interrupted());
}
}
}
/**
* 生产者
*/
class Volatileroduction{
/** 不会产生阻塞的方法*/
public void VolatileProducers1(boolean cancel) throws InterruptedException {
int sum=0;
while (sum < 10000 && !cancel){
if (sum %100 ==0){
System.out.println(sum);
}
sum++;
Thread.sleep(10);
}
}
//此方法在线程处于阻塞状态时,使用volatile并不会是线程中断
public void VolatileProducers2(boolean cancel,BlockingQueue queue) throws InterruptedException {
int sum=0;
while (sum < 10000 && !cancel){
if (sum %100 ==0){
System.out.println("生产者生产了"+sum);
//当阻塞队列满的时候,会处于阻塞状态,代码无法往下执行,自然无法进行while判段,也就无法中断线程
queue.put(sum);
}
sum++;
}
}
/** interrupt() 方法*/
public void VolatileProducers3(boolean cancel,BlockingQueue queue) throws InterruptedException {
int sum=0;
while (sum < 10000 && !Thread.currentThread().isInterrupted()){
if (sum %100 ==0){
System.out.println("生产者生产了"+sum);
queue.put(sum);
}
sum++;
}
}
}
//消费者
class Consumers{
BlockingQueue queue;
public Consumers(BlockingQueue queue) {
this.queue = queue;
}
public boolean needMoreNum(){
if (Math.random() > 0.95){
return false;
}
return true;
}
}
//main方法调用
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue queue = new ArrayBlockingQueue(10);
/** 生产者生产*/
VolatileProducers producers = new VolatileProducers(queue);
Thread producersthread = new Thread(producers);
producersthread.start();
producersthread.sleep(1000);
/** 消费者*/
Consumers consumers = new Consumers(queue);
while (consumers.needMoreNum()){
System.out.println(consumers.queue.take()+"被消费了");
Thread.sleep(100);
}
System.out.println("无需消费");
//将生产者停止生产
producers.cancel = true;
/** 中断线程*/
//producersthread.interrupt();
}
由以上代码可以看出,中断线程最好还是使用 interrupt()方法
volatile与synchronized 比较
- 性能上,前者要比后者好
- 范围上,volatile只能修饰变量,synchronized可以方法,代码快登
- synchronized会发生阻塞,volatile不会
- volatile 可以保证数据可见性,不能保证原子性。synchronized可以保证原子性,也可以间接保证可见性。
- 线程安全包含原子性和可见性两个方面。