Runnable/Thread可能存在的误解

8 浏览
0 Comments

Runnable/Thread可能存在的误解

我不确定我是否正确理解了线程,有人可以告诉我在下面的示例中我是否正确吗?

class Task {
    String taskName;
    private Thread thread;
    boolean isFinished;
    
    public Task(String name){
        taskName = name;
    }
    
    public void createTask(final Runnable r) {
        thread = new Thread(r){
            public void run(){
                if(r != null) {
                    r.run();
                    isFinished = true;
                }
            }
        };
        thread.start();
    }
}

实际上,在我的应用程序中,我将`isFinished`设置为`true`,并且有一个观察者,每当`isFinished`为`true`时,执行一些操作。我担心在我传递的`Runnable`参数中的所有代码实际终止之前,`isFinished`就已经被设置为`true`了。

难道`run`方法不应该将我传递的代码放在一个单独的线程中,并异步地运行该代码吗?

0
0 Comments

从上述内容中可以看出,出现了一个可能的误解,即在代码中没有正确设置isFinished的值。这可能是由于缺少同步或缺少volatile声明导致的数据可见性问题。

另外,代码中还存在一些奇怪之处,即在构造函数中传递了一个Runnable对象,但在调用时使用了方法声明中的引用,而不是线程内部的引用。虽然这种写法“可以工作”,但存在冗余。

另外,感谢Kjäll指出Thread类中只有start方法会创建一个新线程并异步运行,而run方法只是一个普通方法。

解决这个问题的方法是:

1. 确保在代码中正确设置isFinished的值,可以使用同步机制或声明为volatile来解决数据可见性的问题。

2. 修改代码,确保在调用Runnable对象时使用线程内部的引用而不是方法声明中的引用。

3. 检查并确保在使用匿名类时正确使用

下面是修改后的代码示例:

class MyThread extends Thread {
    private volatile boolean isFinished = false;
    private Runnable r;
    public MyThread(Runnable r) {
        this.r = r;
    }
    public boolean isFinished() {
        return isFinished;
    }
    public void run() {
        r.run();
        isFinished = true;
    }
}
public class Main {
    public static void main(String[] args) {
        Runnable myRunnable = new Runnable() {
            public void run() {
                // 代码逻辑
            }
        };
        MyThread myThread = new MyThread(myRunnable);
        myThread.start();
        // 其他代码逻辑
        while (!myThread.isFinished()) {
            // 等待线程完成
        }
        // 线程完成后的处理逻辑
    }
}

0
0 Comments

(Runnable/Thread possible misconception)这个问题的出现的原因是有人错误地认为在构造函数中传递Runnable并覆盖Thread的run()方法是一种正确的做法。根据上述代码的比较,这两种方式实质上是相同的。然而,这种误解可能导致代码的混乱和不一致。

解决这个问题的方法是使用一种更简洁和一致的方式来创建并启动Thread。可以通过传递Runnable对象到Thread的构造函数中,并调用start()方法来实现。以下是解决方法的代码示例:

public void createTask(final Runnable r) {
    Thread thread = new Thread(r);
    thread.start();
}

以上代码将创建一个新的Thread对象,并通过传递Runnable对象r到构造函数中来关联它们。然后,调用start()方法来启动线程。

在解决这个问题的过程中,还需要注意一个潜在的问题,即isFinished变量的线程安全性。为了确保多个线程正确地访问和更新isFinished变量,需要使用volatile关键字来修饰它。以下是修复后的代码示例:

private volatile boolean isFinished;
public void createTask(final Runnable r) {
    Thread thread = new Thread(r);
    thread.start();
    isFinished = true;
}

通过将isFinished变量声明为volatile,可以确保任何对它的写操作都对其他线程可见,从而避免了潜在的线程安全问题。

总结起来,应该避免将Runnable对象传递给Thread的构造函数并覆盖run()方法,而是通过传递Runnable对象到构造函数中并调用start()方法来创建和启动线程。此外,还应该注意变量的线程安全性,特别是对于多线程访问的变量,应该使用volatile关键字来确保其可见性。

0
0 Comments

从这段内容中我们可以看出,问题出现的原因是作者对于Runnable和Thread的使用产生了误解。作者原本希望创建一个新的线程来执行给定的任务,并在任务执行完毕后将isFinished标志设置为true。但是作者错误地将给线程传递了一个Runnable对象,而不是一个Thread对象。因此,任务会直接在当前线程中执行,而不会创建新的线程。

为了解决这个问题,作者需要将给线程传递一个新的Runnable对象,该对象的run()方法会调用给定的任务的run()方法,并在任务执行完毕后将isFinished标志设置为true。

此外,还有isFinished的线程不安全性,并建议添加同步来确保线程能正确地获取到任务执行完毕的状态。作者推荐添加getIsFinished()和setIsFinished()方法,并在这些方法中使用synchronized关键字来保证线程安全。

最后,作者指出了如果没有正确地进行同步,那么可能会出现其他的线程安全问题。这取决于任务的run()方法和其他的“观察者”是否在没有同步的情况下共享数据。

总结起来,这段内容通过修正代码和添加同步来解决了作者对于Runnable和Thread使用的误解,并提醒了作者可能存在的其他线程安全问题。

0