AFP*_*555 1 java multithreading
我一直在学习线程,是的...我是一个noobie.我有一个问题,我不知道如何停止线程,因为方法.spot()已被弃用.我想知道如何安全地停止一个线程.我这样做了:
public class Principal{
private boolean bo1;
private Thread tr1;
public Principal(){
bo1 = true;
tr1 = new Thread(){
public void run(){
while(bo1){
//What the Thread does goes here, its a chronometer.
}
}
}; // The thread body stops here.
} // The constructor body stops here.
public void changeBo1(){
if(bo1 == true){
bo1 = false;
}
else{
bo1 = true;
}
} //Change bo1 ends here.
} //Class ends here.
Run Code Online (Sandbox Code Playgroud)
所以我正在为自己做一个迷你游戏,而我的方法体是一个计时器,它向我展示了我需要多长时间来解决这个难题.这笔交易是,当我开始新游戏时,我调用重置秒,分钟和小时值以及changeBo1()的方法,以便时钟停止.然后,当我在屏幕上第一次点击时,时钟开始.然后,当我改变游戏时.但线程没有读取布尔值的变化,它重新开始到0:00:00,没有我点击屏幕,继续到0:00:01 ---(这不会发生在第一个游戏,因为变量是需要的,当我点击"新游戏"时,当变量需要改变时,就会发生变化.
如何让线程读取boolean bo1的变化?
首先,将volatile关键字添加到bo1:
private volatile boolean bo1;
Run Code Online (Sandbox Code Playgroud)
该volatile关键字保证当任何线程写入变量,任何后续读取任何其他线程将读取更新后的值.缺少关键字可能会导致一些不合需要的优化,基于假设变量仅在每个线程的基础上使用.
您的功能changeBo1()也可以简化为:
public void changeBo1() {
bo1 = !bo1;
}
Run Code Online (Sandbox Code Playgroud)
编辑1:另一种方法是这样做:
tr1.interrupt();
Run Code Online (Sandbox Code Playgroud)
这对你有两件事:
tr1调用Object.wait();,则中断标志将释放线程上的块,因此可以关闭.您将不再需要布尔值来跟踪线程何时应该中断; 您可以在里面使用以下代码段run():
while(!isInterrupted()){
...
}
Run Code Online (Sandbox Code Playgroud)使bo1 易变:
private volatile boolean bo1;
Run Code Online (Sandbox Code Playgroud)
这是因为,有时一个线程可以在另一个线程更改该值后读取过时值.对此的简单解释是每个线程都有自己的内存副本,两个线程共享,有时该私有副本可能不同步.
bo1是通常所说的sentinel变量.只是一种说法变量控制循环的奇特方式.
请记住,两个线程不同步,因此它们可以处于任何状态.你必须小心控制这种状态.仅仅因为你设置bo1为false并不意味着使用它作为sentinel变量的线程实际上已经完成执行,因为它可能尚未处理此更改并退出循环.
您需要连接线程以确保执行完成.如果join Thread1 调用Thread2,则Thread1将被阻塞,直到Thread2完成执行.(调用join自身的线程不会被阻止.)
这是一个重写,使用上面提到的技术.
public class Principal{
private boolean bo1;
private Thread tr1;
public Principal(){
bo1 = true;
tr1 = new Thread(){
public void run(){
while(bo1){
//What the Thread does goes here, its a chronometer.
}
}
}; // The thread body stops here.
} // The constructor body stops here.
public void stopThread(){
changeBo1();
tr1.join();
}
public void changeBo1(){
bo1 = !bo1;
} //Change bo1 ends here.
} //Class ends here.
Run Code Online (Sandbox Code Playgroud)
如果您遇到需要循环处理数据的情况(例如解析流协议,或只是处理某些项目列表),那么遵循这样的模式可能会很有用:
public class ProcessRunnable implements Runnable{
private final Queue<Item> queue = new LinkedList<Item>();
public void run(){
while(active){
synchronized(queue){
while(queue.size()>0){
Item item = queue.remove();
//process item
}
queue.wait();
}
}
}
public void add(Item item){
synchronized(queue){
this.queue.add(item);
this.queue.notifyAll();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这会调出通知和等待功能.调用Wait一个对象将阻塞一个线程,直到另一个线程调用notify或notifyAll在同一个对象上.这可以用于指示数据可用,或者更一般地,已经发生了一些值得注意的事件.这是必要的,因为不等待将导致线程尽可能快地运行,消耗大量CPU.