#java #multithreading #runnable
#java #многопоточность #runnable
Вопрос:
Я пытаюсь понять потоки на 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__";
}
}
The 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 amp;amp; Thread.getAllStackTraces().keySet().contains(thread));
if(null == thread || !threadIsAlive) {
thread = new Thread(this);
thread.start();
} else {
thread.run();
}
}
}
Комментарии:
1. Как запустить поток?
2. вы должны выполнить
myThread.start();
, чтобы запустить его в другом потоке3. Забыл добавить этот код. Отредактировал мой вопрос. Я думаю, что это решает мой вопрос
4.
myThread.runThread()
просто вызовет этот метод в текущем потоке. Если вы хотите, чтобы это было выполнено в новом потоке, поместите этот вызов вrun
метод и просто вызовитеthread.start()
. это запускает другой поток и вызывает метод run вашего runnable объекта.5. Если вам требуется создать новый поток в
while
цикле, пожалуйста, поместите инструкцииThread
creating вrunThread
метод
Ответ №1:
thread.run();
просто вызывает ваш Runnable
s run
метод напрямую, в контексте текущего потока. Вы получите тот же результат, если вас просто вызовут run()
в вашем runThread
методе.
Вам нужно вызвать thread.start()
, это создаст новый поток процесса и в конечном итоге вызовет ваш Runnable
s run
метод
Вместо того, чтобы Thread
вместо a Runnable
оборачивать a, что противоречит здравому смыслу и, как правило, плохой дизайн, вы должны создать 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());
Ответ №2:
myThread.runThread()
просто вызовет этот метод в текущем потоке. Если вы хотите, чтобы это было выполнено в новом потоке, поместите этот вызов в run
метод и просто вызовите myThread.start()
. Это запускает другой поток и вызывает метод run вашего runnable объекта.
Ответ №3:
Когда вы определяете класс, который реализует Runnable, вам не нужно иметь в нем объект Thread.
Упрощенно
class myThread implements Runnable {
@Override
public void run() {
// do something
}
}
new Thread (new myThread ()).start ();
Ответ №4:
Я не пытался понять ваш пример (слишком запутанный), но это плохая идея:
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...
}
}