Понимание потоков, реализующих Runnable в 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, где выполняется dataContainer.toString() из основного класса и экземпляра myThread, я получаю вывод, поскольку все они выполняются в одном потоке: main thread. Ни одно из исполнений в цикле не выполняется с Thread 2.

Моя цель состоит в том, чтобы in the while loop, I want myThread.runThread() выполнялось в потоке Thread 2.

ИЗМЕНИТЬ:

Добавлено thread.start(). Однако теперь он выполняется только один раз? Я не могу создавать новый поток каждый раз, когда хочу выполнить myThread.runThread(). Создав новый поток в цикле, я в конечном итоге создал кучу потоков. Это целесообразно? Я хочу, чтобы определенный фрагмент кода (скажем, Y) выполнялся потоком (скажем, X). Каждый раз, когда нужно выполнить 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();
        }
    }
}

person user2749184    schedule 03.07.2014    source источник
comment
Как вы начинаете обсуждение?   -  person Sotirios Delimanolis    schedule 03.07.2014
comment
вам нужно запустить myThread.start();, чтобы запустить его в другом потоке   -  person Subin Sebastian    schedule 03.07.2014
comment
Забыл добавить этот код. Отредактировал мой вопрос. Я думаю, это решает мой вопрос   -  person user2749184    schedule 03.07.2014
comment
myThread.runThread() просто вызовет этот метод в текущем потоке. Если вы хотите, чтобы это выполнялось в новом потоке, поместите этот вызов в метод run и просто вызовите thread.start(). это запускает другой поток и вызывает метод запуска вашего запускаемого объекта.   -  person Subin Sebastian    schedule 03.07.2014
comment
Если вам нужно создать новый поток в цикле while, поместите операторы создания Thread в метод runThread.   -  person A Stranger    schedule 03.07.2014
comment
в ответ на ваш edit вам нужно поместить экземпляр вашего потока в цикл.   -  person Scary Wombat    schedule 03.07.2014
comment
@AStranger, ScaryWombat, таким образом я бы создал кучу тем. Это целесообразно? Проще говоря, я хочу, чтобы определенный фрагмент кода выполнялся в другом потоке (скажем, X). И каждый раз, когда я хочу выполнить код, это нужно делать только через X-поток.   -  person user2749184    schedule 03.07.2014
comment
Да, это опасно, и я думаю, что Java может создать максимальное количество потоков. Если вам нужно многократно запускать набор операторов в то время как lopp, какой смысл в потоках? я тебя не понимаю   -  person A Stranger    schedule 03.07.2014


Ответы (4)


thread.run(); просто напрямую вызывает ваш метод Runnables run в контексте текущего потока. Вы получите тот же результат, если просто вызовете run() в своем runThread методе.

Вам нужно вызвать thread.start(), это создаст новый поток процесса и в конечном итоге вызовет ваш метод Runnables run

Вместо того, чтобы оборачивать 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());
person MadProgrammer    schedule 03.07.2014

myThread.runThread() просто вызовет этот метод в текущем потоке. Если вы хотите, чтобы это выполнялось в новом потоке, поместите этот вызов в метод run и просто вызовите myThread.start(). Это запускает другой поток и вызывает метод запуска вашего запускаемого объекта.

person Subin Sebastian    schedule 03.07.2014

Когда вы определяете класс, реализующий Runnable, вам не нужно иметь в нем объект Thread.

упрощенно

 class myThread implements Runnable {

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


new Thread (new myThread ()).start ();
person Scary Wombat    schedule 03.07.2014

Я не пытался понять ваш пример (слишком запутанный), но это плохая идея:

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...
    }
}
person Solomon Slow    schedule 03.07.2014