同样水文一篇,就当学习笔记,大佬自动忽略,本篇来学习一下线程中断相关知识点,alf go!
中断普通线程
有过线程学习经验的小伙伴应该都知道,中断线程的几种方式:
- 退出标志;
- stop强行终止(弃用);
- interrupt
对应Demo:
// 退出标志式
public class StopThreadTest extends Thread{
private boolean exit = false;
@Override
public void run() {
while (!exit) {
try {
System.out.println("别搞我,我在摸鱼");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception{
StopThreadTest thread = new StopThreadTest();
thread.start();
Thread.sleep(4000);
thread.exit = true;
}
}
// interrupt方式
public class InterruptThreadTest extends Thread {
@Override
public void run() {
while (!isInterrupted()) {
try {
System.out.println("别搞我,我在摸鱼");
Thread.sleep(5000);
} catch (InterruptedException e) {
break;
}
}
}
public static void main(String[] args) throws Exception {
InterruptThreadTest thread = new InterruptThreadTest();
thread.start();
Thread.sleep(3000);
thread.interrupt();
}
}
中断线程池中线程
使用线程池提交任务有两种:execute和submit,这两者最大的区别就是后者带有返回值的Future句柄,在Java线程池(一):运行阶段可以修改参数吗中使用过execute方式提交任务,看一下submit方式提交任务:
public class SubmitStopThreadTest {
public static void main(String[] args) throws Exception {
int cpuSize = Runtime.getRuntime().availableProcessors();
// 创建线程池
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
1,
cpuSize * 4,
30,
/*可以指定外部ThreadFactory*/
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(200),
new ThreadPoolExecutor.CallerRunsPolicy()
);
// 执行Runnable,无返回值
poolExecutor.submit(new RunnableTask());
// 带返回值的Runnable
Result result = new Result("我是线程池中带返回值的Runnable骚操作");
Future<Result> runnableFuture = poolExecutor.submit(new RunnableTaskWithResult(result), result);
System.out.println(runnableFuture.get().getData());
// 执行callable类型
Future<String> callableFuture = poolExecutor.submit(new CallableTask());
System.out.println(callableFuture.get());
// 关闭线程池
poolExecutor.shutdown();
}
}
class CallableTask implements Callable<String> {
@Override
public String call() throws Exception {
return "执行Callable任务";
}
}
class RunnableTask implements Runnable {
@Override
public void run() {
System.out.println("执行Runnable任务");
}
}
class RunnableTaskWithResult implements Runnable {
private Result result;
public RunnableTaskWithResult(Result result) {
this.result = result;
}
@Override
public void run() {
this.result.setData("hello 多线程: " + result.getData());
}
}
class Result {
private String data;
public Result(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
// 执行结果:
执行Runnable任务
hello 多线程: 我是线程池中带返回值的Runnable骚操作
执行Callable任务
submit其实内部也是封装的execute方法:
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
所以execute想要得到返回值,可以通过这个方式实现,然后可以拿去futureTask中的执行结果:
FutureTask<String> futureTask = new FutureTask<String>(
new Callable<String>() {
public String call() {
Thread.currentThread().stop();
return "test";
}
});
poolExecutor.execute(futureTask);
这样停止线程可以用调用FutureTask的cancel方法:
futureTask.cancel(true);
public boolean cancel(boolean mayInterruptIfRunning) {
// 设置任务状态
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
// 调用线程的interrupt中断线程
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
// 调用finishCompletion执行任务完成,唤醒并删除所有在waiters中等待的线程
finishCompletion();
}
return true;
}
总结
当然,我觉得线程交由线程池管理,一般不需要我们再去控制其生命周期,所以也只是探讨一下,在线程或线程池里,安全关闭一个线程的方法还是调用interrupt方法啦。