停止Java线程的安全方法
有谁能解释一下为什么第一个线程不工作,而第二个线程工作得很好:停止Java线程的安全方法,java,multithreading,Java,Multithreading,有谁能解释一下为什么第一个线程不工作,而第二个线程工作得很好: public class Test { public static void main(String args[]) throws InterruptedException { TestThread1 t1 = new TestThread1(); TestThread2 t2 = new TestThread2(); t1.startThread(); t
public class Test {
public static void main(String args[]) throws InterruptedException {
TestThread1 t1 = new TestThread1();
TestThread2 t2 = new TestThread2();
t1.startThread();
t2.start();
Thread.sleep(4000);
t1.stopThread();
t2.stopThread();
}
}
class TestThread1 extends Thread {
private volatile TestThread1 thread;
public void startThread() {
thread = new TestThread1();
thread.start();
}
public void run() {
while (thread != null) {
System.out.println("RUNNING 1 ...");
}
}
public void stopThread() {
thread = null;
}
}
class TestThread2 extends Thread {
private volatile boolean finished = false;
public void run() {
while (!finished) {
System.out.println("RUNNING 2 ...");
}
}
public void stopThread() {
finished = true;
}
}
当我在TestThread1
类内部调试时:在startThread
内部,将填充thread
成员(因此它不是null
),在run
内部,thread
成员是null
!!!最后,在stopThread
内部,thread
成员不是null
有人能向我解释一下这里发生了什么事吗
TestThread1 t1 = new TestThread1();
t1.startThread();
这将简单地调用对象t1上的方法startThread()
。在这个方法中,您正在创建一个新线程
thread = new TestThread1();
thread.start();
但是对于这个线程,Thread
实例变量为null(对于t1它不是null)
所以在这两种情况下,线程变量都应该为null
这将简单地调用对象t1上的方法startThread()
。在这个方法中,您正在创建一个新线程
thread = new TestThread1();
thread.start();
但是对于这个线程,Thread
实例变量为null(对于t1它不是null)
因此,在这两种情况下,线程变量都应该为null。正在创建两个TestThread1对象,一个启动,另一个停止
我建议不要扩展线程,而是将Runnable包装一次。正在创建两个TestThread1对象,一个启动,另一个停止
我建议不要扩展Thread,而是将Runnable包装一次。因为在main方法中创建了Thread1对象。然后运行startThread,它在第一个Thread1对象中创建一个不同的Thread1对象,并将其设置为字段thread。然后启动第二个对象,该对象没有初始化自己的线程字段。在第二个对象上运行run方法时,条件为false,while循环不会启动 对象层次结构如下所示
t1 (Thread1) {
thread(Thread1): {
thread: null;
run() {
while (thread != null) {...} // this is the method that is run - thread is null here since you never initialized it
}
};
startThread() {} // calls the run method on the nested thread object above
run() {
while (thread != null) {...} // this method is not run since t1.start() is never called in main()
}
}
因为在main方法中创建了Thread1对象。然后运行startThread,它在第一个Thread1对象中创建一个不同的Thread1对象,并将其设置为字段thread。然后启动第二个对象,该对象没有初始化自己的线程字段。在第二个对象上运行run方法时,条件为false,while循环不会启动 对象层次结构如下所示
t1 (Thread1) {
thread(Thread1): {
thread: null;
run() {
while (thread != null) {...} // this is the method that is run - thread is null here since you never initialized it
}
};
startThread() {} // calls the run method on the nested thread object above
run() {
while (thread != null) {...} // this method is not run since t1.start() is never called in main()
}
}
这里有两个
testthread1t1
的实例:
- 一个存储在
局部变量中(在t1
方法中)main
- 一个存储在
实例变量中(属于线程
)t1
t1
从未启动,t1。线程
未启动
t1.stopThread()
将t1.thread
设置为null
,但它不会影响t1.thread.thread
由于您正在启动t1.thread
,其run
方法使用t1.thread.thread
:
- 这永远不会设置为任何值(因此它使用的是
)null
- 像您这样调用
只会将t1.stopThread()
设置为t1.thread
,这不会影响null
t1.thread.thread
更一般地说,您不能仅仅“杀死”线程本身,而是可以在方法中实现测试,以告诉它在某些情况下返回。您在第二个测试中所做的更接近于此(使用
而(!finished){…}
和一个volatile变量)
我不会将测试限制为完成
。测试线程是否被中断也很有用,特别是因为如果在ExecutorService
shutdownNow()
中运行可运行程序,将尝试中断它们(请参阅)
我会在(!finished&&!Thread.currentThread().isInterrupted()){…}时使用
(请注意Thread.currentThread().isInterrupted()
和Thread.interrupted()
之间的区别:它们可能看起来相似,但后者也会重置状态,这可能是您不希望的。)
根据循环中的内容(或者是否存在循环),您可能希望在不同的策略点使用类似于if(finished | | Thread.currentThread().isInterrupted()){return;}
,在这里,您有两个testthread1t1
的实例:
- 一个存储在
t1
局部变量中(在main
方法中)
- 一个存储在
线程
实例变量中(属于t1
)
t1
从未启动,t1。线程
未启动
t1.stopThread()
将t1.thread
设置为null
,但它不会影响t1.thread.thread
由于您正在启动t1.thread
,其run
方法使用t1.thread.thread
:
- 这永远不会设置为任何值(因此它使用的是
null
)
- 像您这样调用
t1.stopThread()
只会将t1.thread
设置为null
,这不会影响t1.thread.thread
更一般地说,您不能仅仅“杀死”线程本身,而是可以在方法中实现测试,以告诉它在某些情况下返回。您在第二个测试中所做的更接近于此(使用而(!finished){…}
和一个volatile变量)
我不会将测试限制为完成
。测试线程是否被中断也很有用,特别是因为如果在ExecutorService
shutdownNow()
中运行可运行程序,将尝试中断它们(请参阅)
我会在(!finished&&!Thread.currentThread().isInterrupted()){…}
时使用
(请注意Thread.currentThread().isInterrupted()
和Thread.interrupted()
之间的区别:它们可能看起来相似,但后者也会重置状态,您可能不希望这样做。)
t1.startThread();
t2.start();