从“实践中的java并发”一书中,有一个声明 - > if the task is not responsive to interruption, timedRun will not return until the task finishes, which may be long after the desired timeout
private static final ScheduledExecutorService cancelExec = ...;
public static void timedRun(Runnable r,
long timeout, TimeUnit unit) {
final Thread taskThread = Thread.currentThread();
cancelExec.schedule(new Runnable() {
public void run() { taskThread.interrupt(); }
}, timeout, unit);
r.run();
}
这是否意味着interrupt()函数可能会卡住?什么可能导致中断()卡住。它只是设置目标线程的isInterrupted标志。我预见除非并且直到任何进程可能使正在调用interrupt()的进程饿死,我认为中断函数不会卡住。
答案 0 :(得分:2)
不,这意味着如果r
没有以某种方式检查run
期间的中断,则中断它将无法执行任何操作。
这种方法的结构非常复杂。
public static void timedRun(Runnable r,
long timeout, TimeUnit unit) {
// reference to the thread calling the method
final Thread taskThread = Thread.currentThread();
cancelExec.schedule(new Runnable() {
public void run() { // another thread is
taskThread.interrupt(); // scheduled to interrupt
} // the calling thread later
}, timeout, unit);
r.run(); // run a long running task on the calling thread
// this is where interrupt may or may not be seen later
// this is the "task" the blurb is referring to
}
如果我按以下方式调用此方法:
timedRun(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
try {
Thread.sleep(2000L);
} catch(InterruptedException e) {}
System.out.println(System.currentTimeMillis() - start);
}
}, 1L, TimeUnit.SECONDS);
它将输出1000
左右的内容,因为中断会导致在睡眠期间抛出异常。
如果我这样做:
timedRun(new Runnable() {
@Override
public void run() {
while(!Thread.interrupted()) {
/* do whatever */
}
}
}, 1L, TimeUnit.SECONDS);
因为我正在检查它,所以在1秒后它也会看到中断。
如果我这样做:
timedRun(new Runnable() {
@Override
public void run() {
while(true);
}
}, /* doesn't matter */, /* doesn't matter */);
永远不会回来。程序可能会冻结。
答案 1 :(得分:1)
关键是timedRun
在r.run()
返回之前无法返回。如果Runnable r
忽略了它已被中断的事实,那么r.run()
可能会很晚才返回。不是interrupt
调用被卡住(它可能几乎立即完成),而是它的目标可以忽略中断,阻止timedRun
完成,直到run
方法到达它的自然结束,如果有的话。
答案 2 :(得分:0)
另一个解决方案可能是,另一个线程执行长时间运行的任务,调用程序线程(调用“timedRun”的线程)等待任务完成,如下所示:
/**
* Runs a long running task with a timer.
*
* @param longRunningTask long running task
* @param timeout as milliseconds, method will return if long running task is not completed by this time
* @throws InterruptedException
*/
void timedRun(Runnable longRunningTask, long timeout)
throws InterruptedException {
// Thread that executes runnable
Thread newThread = new Thread(longRunningTask);
newThread.start();
// Current thread joins the new thread with a timeout
Thread.currentThread().join(timeout);
// Time expired, longRunningTask might be completed or not
newThread.interrupt(); //optional
}
答案 3 :(得分:0)
这里混淆的一点是作者在方法timedRun的参数中引入了Runnable r这个参数。
我正试图通过删除该参数并引入新任务来简化它。
让我们考虑我们的TimedRun类重新创建如下
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TimedRun {
public static final ScheduledExecutorService cancelExec = new ScheduledThreadPoolExecutor(
1);
public static void timedRun(long timeout, TimeUnit unit) {
final Thread taskThread = Thread.currentThread();
System.out.println(taskThread);
cancelExec.schedule(new Runnable() {
public void run() {
taskThread.interrupt();
}
}, timeout, unit);
runAnytask();
}
private static void runAnytask() {
System.out.println(Thread.currentThread());
while (true) {
// do some work here infinitely
}
}
让我们创建一个方法timedRun的调用者,如下所示
import java.util.concurrent.TimeUnit;
public class TimedRunCaller {
public static void main(String[] args) {
TimedRun.timedRun(1L, TimeUnit.SECONDS);
System.out.println("Now it should terminate");
TimedRun.cancelExec.shutdown();
}
}
这里作者想说,如果任务(在我们的例子中是方法runAnytask)没有响应中断,则使用此runAnytask作为任务的timedRun方法将不会返回给调用者任务(runAnytask)完成。但请注意,runAnytask方法无限循环。所以它永远不会完成。
虽然timedRun方法正在中断调用者线程(这里timedRun方法的调用者是主线程),但runAnytask方法没有响应中断的机制。所以timedRun方法永远不会返回给调用者。
但是如果我们以下面的方式修改我们的runAnytask
private static void runAnytask() {
System.out.println(Thread.currentThread());
long start = System.currentTimeMillis();
try {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("interupted");
break;
}
}
} catch (Exception e) {
System.out.println("interuptrd "
+ (System.currentTimeMillis() - start));
}
}
我们可以看到现在任务响应中断,它将响应timedRun方法引发的中断。它将在指定的超时后返回给调用者。
所以作者说你应该知道规则:在中断之前你应该知道一个线程的中断策略。它是否是为了响应中断而设计的。否则你的中断就像我们在第一个runAnytask方法中那样被忽视。 / p>
我希望现在能清除所有内容。