1

我一直在学习线程,是的……我是个菜鸟。我有一个问题,我不知道如何停止线程,因为方法 .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.

所以我正在为自己制作一个迷你游戏,我的方法的主体是一个计时器,它告诉我我要花多长时间来解决这个难题。交易是,当我开始一个新游戏时,我调用重置秒、分钟和小时值的方法以及 changeBo1() 以便时钟停止。然后当我第一次点击屏幕时,时钟开始。然后,当我改变游戏时。但是线程没有读取布尔值的变化,它重新启动到 0:00:00,并且没有我点击屏幕,继续到 0:00:01---(这不会发生在第一个游戏,因为变量是需要的变量,所以当我点击“新游戏”时会发生这种情况,当变量需要改变时)。

我如何需要允许线程读取布尔 bo1 的变化?

4

4 回答 4

6

首先,将volatile关键字添加到bo1

private volatile boolean bo1;

volatile 关键字保证当任何线程写入变量时,任何其他线程的后续读取都读取更新后的值。基于变量仅在每个线程基础上使用的假设,缺少关键字可能会导致一些不希望的优化。

您的功能changeBo1()也可以简化为:

public void changeBo1() {
    bo1 = !bo1;
}

编辑 1: 另一种方法是这样做:

tr1.interrupt();

这为您做了两件事:

  1. tr1如果调用内部的操作Object.wait();,中断标志将释放线程上的块,因此可以关闭它。
  2. 您将不再需要一个布尔值来跟踪线程何时应该中断;您可以在里面使用以下代码段run()

    while(!isInterrupted()){
        ...
    }
    
于 2013-07-05T04:56:46.837 回答
6

使 bo1不稳定

private volatile boolean bo1;

这是因为,有时,一个线程可以在另一个线程更改该值之后读取一个过时的值。对此的简单解释是每个线程都有自己的两个线程共享的内存副本,有时该私有副本可能不同步。

bo1是通常所说的哨兵变量。只是一种说变量控制循环的奇特方式。

请记住,两个线程不同步,因此它们可以处于任何状态。您必须小心控制该状态。仅仅因为您设置bo1为 false 并不意味着将其用作哨兵变量的线程实际上已完成执行,因为它可能尚未处理此更改并退出循环。

您需要加入线程以确保执行完成。如果 Thread1 调用join 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.

如果您曾经处于需要循环处理数据的情况(例如解析流协议,或者只是处理一些项目列表),那么遵循如下模式可能会很有用:

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();
        }
    }
}

这带来了通知等待功能。调用Wait一个对象将阻塞一个线程,直到另一个线程调用notify或调用notifyAll同一个对象。这可以用来表示数据可用,或者更一般地说,一些值得注意的事件已经发生。这是必要的,因为不等待会导致线程尽可能快地运行,从而消耗大量 CPU。

于 2013-07-05T05:03:30.337 回答
2

要首先停止线程,您需要一个条件变量。在你的情况下

private boolean bo1; // should declare it volatile

第二个非常重要的一点,您需要中断要停止的相应线程。因为您的线程可能正在等待 (wait()) 并且不会检查条件变量,因此不会停止。

即你需要打电话

tr1.interrupt(); // interrupts the  thread and brings out of wait state

永远记住一个线程只有在它的完整运行方法正常/或通过一些异常时才会死亡/停止。

于 2013-07-05T05:31:29.920 回答
0

方法一

正如其他人回答的那样,bo1应该用volatile关键字修改。那些访问块可能会被synchronized关键字修改。

class MyThread extends Thread {

    public void run() {
        while (true) {
            synchronized(this) {
                if (stop) {
                    break;
                }
            }
            // do your job
        }
    }

    public synchronized void setStop() {
        stop = true;
    }

    private volatile stop = false;
}

方法二

线程中断有一个方便的方法。检查Thread#isInterrupted()

class MyThread extends Thread {

    public void run() {
        while (!isInterrupted()) {
            // do your job
        }
    }

    public static void main(final String[] args) throws InterruptedException {
        final Thread thread = new MyThread();
        thread.start();
        Thread.currentThread().sleep(10000L);
        thread.interrupt();
    }
}
于 2013-07-05T05:48:19.030 回答