停止线程

当在外部打断一个线程时,如果这个线程到达了某个变量标记的测试或者程序员准备好的离开该方法的其他地方,则线程可以较容易的安全的结束;但有时候我们需要在run()方法中间突然断掉线程,这时可能需要清理资源。

一个程序在执行时可能会开启多个线程。由于某些原因,我们需要关闭它们,这时最好的做法是做好善后的工作使线程有序安全的结束。

结束线程的一些方法。

1、Thread.stop()方法。此方法已弃用 , 不考虑使用。

API文档中关于stop()方法的描述。

这种方法本质上是不安全的。 使用Thread.stop停止线程可以解锁所有已锁定的监视器(由于未ThreadDeath
ThreadDeath异常在堆栈中ThreadDeath的自然结果)。
如果先前受这些监视器保护的任何对象处于不一致的状态,则损坏的对象将变得对其他线程可见,可能导致任意行为。stop许多用途应该被代替,只需修改一些变量来指示目标线程应该停止运行。
目标线程应该定期检查此变量,如果变量表示要停止运行,则以有序方式从其运行方法返回。
如果目标线程长时间等待(例如,在interrupt变量上),则应该使用interrupt方法来中断等待。

stop()方法使用时非常干脆,他会立即结束当前线程。但他会留下许多问题,比如破坏数据安全性和没有正确关闭资源。

2、Thread.interrupt()方法。

中断Object类的wait()、wait(long)、或wait(long, int),Thread类的join()、join(long)、join(long, int)、sleep(long)、或sleep(long, int)方法。
当线程由于上面的方法进入中断状态时,调用此方法可以清除其中断状态并收到一个InterruptedException,从而达到结束一个线程(并不是一调用就结束线程,而是转到异常处理语句)。
如果当前线程不能修改此线程,抛出SecurityException异常

代码:
public class Demo_1 extends Thread {
	public static void main(String[] args) throws InterruptedException {
		Demo_1 d1 = new Demo_1();
		d1.start();
		......
		System.out.println("Thread ready interrupt...");
		d1.interrupt();
		......
		System.out.println("Main stop");
	}

	public void run() {
			System.out.println("Thread is runing...");
			try {
				while (true) {
					Thread.sleep(500);
				}
			} catch (InterruptedException e) {System.out.println("Exception1");break;}
			
//			try {
//				Thread.sleep(500);
//			} catch (InterruptedException e) {System.out.println("Exception2");break;}
	}
}
运行结果
Main is start
Thread is runing...
Thread is runing...
Thread is runing...
Thread ready interrupt...
Exception2
java.lang.InterruptedException: sleep interruptedMain stop
	at java.lang.Thread.sleep(Native Method)
	at com.yxj.demo.Demo_1.run(Demo_1.java:30)
	
若取消注释,则有可能打印Exception2

3、Thread.interrupted()方法

此方法与Thread.interrupt()方法作用相同,只是其会返回线程是否中断。
Thread.isinterrupted(),此方法只是判断线程是否中断,不会改变线程中断状态

4、通过周期性的检查共享变量以达到退出线程的目的

public class Demo_2 {

	static boolean falg = true;
	
	public static void main(String[] args) throws InterruptedException {
		T1 t1 = new T1();
		System.out.println("Main is start");
		t1.start();
		......
		System.out.println("Thread ready exit...");
		falg = false;
		......
		System.out.println("Main stop");
	}
}
class T1 extends Thread {
	public void run() {
		while (Demo_2.falg) {
			System.out.println("Thread is runing...");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {e.printStackTrace();}
		}
		System.out.println("Thread is exit...");
	}
}
运行结果
Main is start
Thread is runing...
Thread is runing...
Thread is runing...
Thread is runing...
Thread is runing...
Thread is runing...
Thread ready exit...
Main stop
Thread is exit...

5、关闭一些长时间阻塞的线程。

比如ServerSocket的accept()方法会一直阻塞线程直到接收到数据。由于线程一直阻塞,程序不会循环检查共享变量falg,将falg设为false并不能成功结束线程。此时可以通过其自带的close()方法结束线程,此时所有当前由此ServerSocket引起的阻塞线程都会抛出一个SocketException 。
类似的方法还有DatagramSocket.receive(),IO操作等。

import java.io.IOException;
import java.net.ServerSocket;

public class Demo_3 {
	public static void main(String[] args) throws InterruptedException {
		startServer();
	}

	public static void startServer() throws InterruptedException {
		Server server = new Server();
		System.out.println(Thread.currentThread().getName() + " Server start...");
		server.start();
		......
		System.out.println("main Server ready stop...");
		server.stopServer();
		System.out.println("Main is Stop");
	}
}

class Server extends Thread {
	//新建一个ServerSocket空引用
	ServerSocket ss = null;
	
	//关闭当前阻塞中的线程
	public void stopServer() {
		try {
			System.out.println(Thread.currentThread().getName() + " stopServer");
			if(ss! = null){
				ss.close();
			}
		} catch (IOException e) {e.printStackTrace();}
	}
	//重写run方法
	public void run() {
		try {
			while (true) {
				System.out.println(Thread.currentThread().getName() + " is running...");
				ss = new ServerSocket(10000);		//实例化ServerSocket
				ss.accept();	//阻塞
				System.out.println(Thread.currentThread().getName() + " is stop");
			}
		} catch (IOException e) {
			System.out.println(Thread.currentThread().getName() + " get a Exception...");
			e.printStackTrace();
		} finally {
			//正常关闭ServerSocket
			try {ss.close();} catch (IOException e) {e.printStackTrace();}
		}
		System.out.println("Thread is exit");
	}
}
运行结果
main Server start...
Thread-0 is running...
main Server ready stop...
main stopServer
Main is Stop
Thread-0 get a Exception...
java.net.SocketException: socket closed
	at java.net.DualStackPlainSocketImpl.accept0(Native Method)
	at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
	at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:404)
	at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
	at java.net.ServerSocket.implAccept(ServerSocket.java:545)
	at java.net.ServerSocket.accept(ServerSocket.java:513)
	at com.yxj.demo.Server.run(Demo_3.java:41)
Thread is exit

由ServerSocket.close()源码可以看出,close方法先关闭SocketImpl,然后修改一个标记。

主线程main运行close()方法后退出,catch(IOException e){}语句由Thread-0执行

ServerSocket.close()源码
created表示是否已经创建了 SocketImpl 对象,ServerSocket 需要依赖该对象实现套接字操作
    /**
     * Various states of this socket.
     */
    private boolean created = false;
    private boolean bound = false;
    private boolean closed = false;
    private Object closeLock = new Object();
	.......
    /**
     * Closes this socket.
     *
     * Any thread currently blocked in {@link #accept()} will throw
     * a {@link SocketException}.
     *
     * <p> If this socket has an associated channel then the channel is closed
     * as well.
     *
     * @exception  IOException  if an I/O error occurs when closing the socket.
     * @revised 1.4
     * @spec JSR-51
     */
    public void close() throws IOException {
        synchronized(closeLock) {
            if (isClosed())
                return;
            if (created)
                impl.close();
            closed = true;
        }
    }

6、将线程设置为守护线程

一个程序可以开启多个线程,这些线程分为两种:守护线程(daemon thread)和用户线程(user thread)。
守护线程是一种特殊的线程,其特点为:如果程序仅剩下某些守护线程还未执行,那么程序会直接结束运行。
守护线程往往用于可以放弃的任务。

package com.yxj.demo;

public class Demo_4 extends Thread {

	public Demo_4() {
		this.setDaemon(true);
	}

	public static void main(String[] args) throws InterruptedException {
		Demo_4 d4 = new Demo_4();
		System.out.println("Main is start");
		d4.start();
		......
		System.out.println("Main stop");
	}

	public void run() {
		while (true) {
		
			System.out.println("Thread is runing...");
			//此线程一直在执行
			......
		}
		System.out.println("Thread is exit...");			//此语句没有执行
	}
}

运行结果
Main is start
Thread is runing...
Thread is runing...
Thread is runing...
Thread is runing...
Thread is runing...
Thread is runing...
Main stop

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值