繁体   English   中英

了解在Java中实现Runnable的线程

[英]Understanding Threads implementing Runnable in java

我试图了解Java中的线程。 我创建了一个实现Runnable接口的线程,该接口执行某个类的某个功能。 以下是Java类:

MyThread Class

public class MyThread implements Runnable {
    private DataContainer dataContainer;
    private Thread thread;
    public MyThread(DataContainer dataContainer) {
        this.dataContainer = dataContainer;
        thread = new Thread(this);
        thread.start();
        thread.setName("Thread 2");
    }
    @Override
    public void run() {
        System.out.println("MyThread : "+dataContainer.toString());
    }
    public void runThread() {
        thread.run();
    }
}

DataContainer Class 我在线程中执行的功能

public class DataContainer {
    private static DataContainer instance = null;
    private DataContainer() {}
    public static DataContainer getInstance() {
        if(null == instance)
            instance = new DataContainer();
        return instance;
    }
    @Override
    public String toString() {
        return Thread.currentThread().getName()+" : __Data__";
    }
}

main class

public class Launcher {
    public static void main(String[] args) {
        DataContainer dataContainer = DataContainer.getInstance();
        MyThread myThread = new MyThread(dataContainer);

        int i =0;
        while(i++<10) {
            System.out.println("Launcher : "+ dataContainer.toString());
            myThread.runThread();
        }
    }
}

问题是,在while循环中,从主类和myThread实例执行dataContainer.toString()时,我得到了输出,因为它们都在一个线程中运行: main thread 循环中的所有执行都不是从Thread 2执行的。

我的目标是, in the while loop, I want myThread.runThread()在线程Thread 2下执行。

编辑:

添加了thread.start() 但是,现在只执行一次? 我每次想执行myThread.runThread()时都无法创建新线程。 通过在循环中创建一个新线程,我最终将创建一堆线程。 这是明智的吗? 我希望某个线程(例如X)执行某段代码(例如Y)。 每次必须执行Y时,都应该通过线程X完成。

这可能是一种解决方案:

public class MyThread implements Runnable {
    private DataContainer dataContainer;
    private Thread thread = null;
    public MyThread(DataContainer dataContainer) {
        this.dataContainer = dataContainer;
    }
    @Override
    public void run() {
        System.out.println("MyThread : "+dataContainer.toString());
    }
    public void runThread() {
        boolean threadIsAlive = (null!=thread && Thread.getAllStackTraces().keySet().contains(thread));
        if(null == thread || !threadIsAlive) {
            thread = new Thread(this);
            thread.start();
        } else {
            thread.run();
        }
    }
}

thread.run(); 只是在当前线程的上下文中直接调用您的Runnablerun方法。 如果在runThread方法中简单地调用run()runThread获得相同的结果。

您需要调用thread.start() ,这将创建一个新的进程线程,并最终调用您的Runnablerun方法

而不是包装一个Thread ,而不是一个Runnable ,这是违反直觉的,一般不好的设计,您应该创建Thread和设定Runnable到它时,你需要,例如...

public class MyThread implements Runnable {
    private DataContainer dataContainer;
    public MyThread(DataContainer dataContainer) {
        this.dataContainer = dataContainer;
    }
    @Override
    public void run() {
        System.out.println("MyThread : "+dataContainer.toString());
    }
}

然后您可以做类似...

DataContainer dataContainer = DataContainer.getInstance();
MyThread myThread = new MyThread(dataContainer);

Thread thread = new Thread(myThread );
thread.setName("Thread 2");
thread.start();

System.out.println("Launcher : " + dataContainer.toString());

myThread.runThread()只会在当前线程中调用该方法。 如果希望在新线程中执行该调用,请将该调用放入run方法,然后调用myThread.start() 这将启动另一个线程并调用可运行对象的run方法。

在定义实现Runnable的类时,不需要在其中具有Thread对象。

简单地

 class myThread implements Runnable {

     @Override
    public void run() {
          // do something
   }
}


new Thread (new myThread ()).start ();

我没有试图理解您的示例(太费解了),但这是一个坏主意:

public class Foobar implements Runnable {
    private XType x;
    private YType y;
    private Thread thread;

    public Foobar() {
        x = new XType();
        thread = new Thread(this);   //Not in a constructor!!!
        thread.start();
        y = new YType();
    }

    @Override
    public void run() {
        doSomethingWith(y);       // y can be uninitialized at this point.
        doSomethingElseWith(x);   // x can be uninitialized too!!!
    }
}

这种反模式都有一个名字,这就是所谓的“跑冒滴漏this从一个构造函数。” Foobar构造函数启动新线程,并在完全初始化新对象之前为其提供对新Foobar实例(即this )的引用。 Java语言规范不保证当以这种方式发布对象时,该对象在新线程中的外观如何。 (Google用于“安全发布”)

特别是,当首次输入run()方法时,从新线程的角度看,该对象的任何成员变量(包括x !!)似乎都未初始化。

最佳实践:永远不要在构造函数中或构造函数调用的任何辅助方法中使用this方法,也不要将辅助函数声明为final以便子类无法覆盖一个子类并查看未初始化的对象那样。

class Foobar {

    Foobar(...) {
        ...don't use "this" here...
        fooHelper(...);
    }

    private final void fooHelper(...) {
        ...don't use "this" here either...
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM