线程和中断

Threads and interrupt

我有以下代码

package threads;

import java.util.ArrayList;
import java.util.List;

public class Threads extends Thread implements Runnable {

    private final List<Thread> threadList = new ArrayList<>();
    private String f, l;
    private Thread greetings1, greetings;

    public static void main(String[] args) {

        String[] elements = { "Tim", "Fred", "Jeff", "Scott" };
        Threads t = new Threads();
        for (String e : elements) {
            t.threadL(e);

            t.threadR(e);
        }

        for (int index = 0; index < t.threadList.size(); index++) {
            // blank at the moment

        }
    }

    public void threadR(String f) {
        greetings = new Thread(f);

        Thread greetingsFromFred = new Thread(greetings) {

            @Override
            public void run() {
                for (int i = 1; i < 5; i++) {
                    try {
                        System.out.println("Main Thread: " + i + " " + f);
                        Thread.sleep(5000);

                    } catch (InterruptedException ex) {
                        System.out.println("Main thread interrupted.");

                    }
                    System.out.println("Main thread exiting.");
                }
            }
        };
        greetingsFromFred.start();
    }

    public List<Thread> threadL(String l) {
        greetings1 = new Thread(this);

        this.l = l;
        greetings1.start();

        threadList.add(greetings1);

        return (threadList);

    }

    @Override
    public void run() {

        greetings.interrupt(); // interrupt greetings thread here <-------

        System.out.println("Greetings from " + l + "! threadL");

    }
}

当 threadL 运行时,我想从 运行 中断 threadR,因此导致

 System.out.println("Main thread interrupted.");

将从 threadR 打印

我在代码中突出显示了应该发生中断的位置

 greetings.interrupt();  //interrupt greetings thread here <-------

为什么中断不能正常工作?

您需要打断 greetingsFromFred。这是正在启动的线程,实际上是 运行。线程 greetings 永远不会 运行。 Is 仅作为 运行nable 传递给另一个线程。为什么还要在线程的构造函数中传递其他线程?这整个设计很可疑。我认为您对 thread/runnable 以及何时以及如何使用感到困惑。

您要中断的线程称为 greetingsFromFred 而不是 greetings,因此只要您使 greetingsFromFred 可见,此更改就会起作用。

       greetingsFromFred.interrupt();  //interrupt greetings thread here <-------

您的程序有点像线程对象的迷宫。让我们尝试从 main.

跟随它

main 中,您创建了一个类型为 Threads 的对象 t。这意味着它是 ThreadRunnable.

然后,对于您的每个字符串,您 运行 tthreadLthreadR 将该字符串作为参数。

main 的任何地方你都没有真正开始 t,甚至 运行 它的 run 方法直接开始。

然后,在 threadR 中创建一个新的空 Thread 并将其分配给 greetings

然后您使用那个新的空 Thread(问候)作为一个 Runnable,它被传递给一个新的 Thread 对象,该对象的 run 方法也被覆盖。这是徒劳的。在任何情况下,greetingsFromFred 都会启动,并且会 运行 循环。但是 greetings 仍然包含与 greetingsFromFred 线程无关的空 Thread

threadL 中,您创建了另一个 Thread,将当前的 Thread(即 main 中的 t)作为其 运行启用。然后你终于开始了。它将尝试中断 greetings 中的线程,但正如我们所说,这是一个从未启动的非活动空线程。

你的结构应该没有那么复杂。尽可能只使用 Runnable 对象来处理应该执行的事情。因此,Threads 本身应该是 Runnable,而 threadR 应该固定为这样的东西:

public void threadR(String f) {

    Runnable greetingsFromFred = new Runnable() {

        @Override
        public void run() {
            for (int i = 1; i < 5; i++) {
                try {
                    System.out.println("Main Thread: " + i + " " + f);
                    Thread.sleep(5000);

                } catch (InterruptedException ex) {
                    System.out.println("Main thread interrupted.");

                }
                System.out.println("Main thread exiting.");
            }
        }
    };

    greetings = new Thread(greetingsFromFred, f);
    greetings.start();
}

这样,greetings 将是一个 Thread,它将 运行 您在 Runnable[=70= 中创建的 循环],还有名字 f.

但是请注意:由于您实际上并没有在 catch 子句中停止循环,因此当线程被中断时您不会退出循环,并且您可能会得到 "Exiting" 消息打印不止一次,具体取决于中断何时进入循环。

正如其他人所指出的,这里有几个问题。

不必要的继承

您的 class Threads 有一个 run() 方法可以中断分配给 greetings 的任何线程,但 RL 都不会继承 run() 方法。 R 扩展了 Thread 并覆盖了 run(),而 L 只是扩展了 Thread 而没有覆盖。这种结构没有意义。

鉴于此,run() 方法似乎应该被 L 覆盖。

如果您做到了,那么 Threads 就没有必要覆盖 Thread 或实施 Runnable。您可以完全取消它并让 RL 各自覆盖 Thread(使用 Thread(String) 构造函数)。

public class Threads {
...
    public List<Thread> threadL(String l) {
        greetings1 = new Thread(l) {
            @Override
            public void run() {
                greetings.interrupt(); // interrupt greetings thread here <-------
                System.out.println("Greetings from " + l + "! threadL");
            }
        ...
    }
}

所以现在 threadR() 创建并启动一个将被中断的新 Thread,并且 threadL() 创建并启动一个将中断的新 Thread,并且 Threads 仅存在于 main() 方法和 threadR()threadL() 中的线程 creation/starting。清洁工

中断错误的线程

正如其他人所指出的,您有这个不必要的变量 greetingsFromFred,这只会使事情复杂化。你为 greetingsFromFred 所做的一切你应该为 greetings 做(构造函数除外)。

public void threadR(String f) {
    greetings = new Thread(f) {

        @Override
        public void run() {
            ...
        }
    greetings.start();
}

greetings

上的竞争条件

这是最微妙的部分,IMO。您正在使用静态变量 greetings 来保存当前 Thread 对象 R,当前 L 应该中断该对象。但是这两个线程之间没有协调。没有理由相信每个 L 都会在 greetings 中看到一个独特的 R。这是一件非常糟糕的事情。你需要做的是让 greetings volatile,然后让 R 等到 greetings 为空再赋值,让 L 等到 greetings ] 在中断之前不为空。

private volatile Thread greetings;
...
public void threadR(String f) {
    while (greetings != null);
    greetings = new Thread(f) {
...
public void threadL(String l) {
    Thread greetings1 = new Thread(l) {
        @Override
        public void run() {
            while (greetings == null);
...

注意 while(...); 的用法。尾随的分号是一个空语句。这个结构只是说继续检查条件直到它为假,然后继续。由于 R 直到它有一个 null 然后设置它才会继续,并且 L 永远不会继续直到它有一个 non-null 然后将其置空,它们将始终保持同步.