Разбиране на нишките, внедряващи 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 може да създаде. Ако трябва да изпълнявате набор от изрази многократно в while 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