Если метод equals()
присутствует в классе java.lang.Object
, и ожидается, что он проверяет эквивалентность состояния объектов! Это означает, что содержимое объектов. В то время как ожидается, что оператор ==
проверяет, что фактические экземпляры объекта одинаковы или нет.
Пример
Рассмотрим две различные ссылочные переменные, str1
и str2
:
str1 = new String("abc");
str2 = new String("abc");
Если вы используете equals()
System.out.println((str1.equals(str2))?"TRUE":"FALSE");
, вы получите выход как TRUE
, если вы используете ==
.
System.out.println((str1==str2) ? "TRUE" : "FALSE");
Теперь вы получите вывод FALSE
в качестве вывода, потому что оба str1
и str2
указывают на два разных объекта, хотя оба они имеют одинаковое строковое содержимое. Именно из-за new String()
каждый новый объект создается каждый раз.
Не используйте конструкции низкого уровня, такие как потоки, если Вам абсолютно не нужны питание и гибкость.
Можно использовать ExecutorService, такой как ThreadPoolExecutor к отправьте () Callables. Это возвратит будущий объект.
Используя это Future
объект, который можно легко проверить, сделан ли он и получает результат (включая блокирование get()
если это еще не сделано).
Те конструкции значительно упростят наиболее распространенные потоковые операции.
Я хотел бы разъясниться о блокировании get()
:
Идея состоит в том, что Вы хотите выполнить некоторые задачи ( Callable
s) это делает некоторую работу (вычисление, доступ ресурса...), где Вам не нужен результат прямо сейчас. Можно просто зависеть от Executor
выполнять Ваш код каждый раз, когда это хочет (если это - a ThreadPoolExecutor
затем это будет работать каждый раз, когда свободный Поток доступен). Затем в какой-то момент вовремя Вам, вероятно, нужен результат вычисления для продолжения. В этой точке Вы, как предполагается, звоните get()
. Если задача уже работала в той точке, то get()
просто сразу возвратит значение. Если задача не завершалась, то get()
вызов будет ожидать, пока задача не выполнена. Это обычно желаемо, так как Вы не можете продолжить без результата задач так или иначе.
Когда Вы не нуждаетесь в значении для продолжения, но хотели бы знать об этом, если это уже доступно (возможно для показа чего-то в UI), затем можно легко звонить isDone()
и только звоните get()
если это возвращается true
).
Ваш сценарий все еще немного неясен.
При выполнении пакетного задания можно хотеть использовать invokeAll
. Это заблокирует Ваш основной поток, пока все задачи не будут завершены. Нет никакого "активного ожидания" с этим подходом, где основной поток потратил бы впустую ЦП, опрашивающий isDone
метод будущего. В то время как этот метод возвращает список Futures
, они уже "сделаны". (Существует также перегруженная версия, которая может тайм-аут перед завершением, которое могло бы быть более безопасно использовать с некоторыми задачами.) Это может быть намного более чисто, чем попытка собрать набор Future
объекты самостоятельно и пытающийся проверить их состояние или заблокировать их get
методы индивидуально.
Если это - интерактивное приложение с задачами, эпизодически отделенными, чтобы быть выполненным в фоновом режиме, использование обратного вызова, как предложено nick.holt является большим подходом. Здесь, Вы используете submit
a Runnable
. run
метод вызывает обратный вызов с результатом, когда он был вычислен. С этим подходом можно отбросить Future
возвращенный submit
, если Вы не хотите смочь к cancel
выполняющиеся задачи, не закрывая целое ExecutorService
.
Если Вы хотите смочь отменить задачи или использовать возможности тайм-аута, важная вещь помнить состоит в том, что задачи отменяются путем вызова interrupt
на их потоке. Так, Ваша задача должна периодически проверять свое прерванное состояние и прерываться по мере необходимости.
Вы могли создать интерфейс lister, что основные реализации программы, который называет рабочий, после того как он закончил выполняться, это - работа.
Тем путем Вы не должны опрашивать вообще.
Вот интерфейс в качестве примера:
/**
* Listener interface to implement to be called when work has
* finished.
*/
public interface WorkerListener {
public void workDone(WorkerThread thread);
}
Вот пример фактического потока, который делает некоторую работу и уведомляет, что это - слушатели:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Thread to perform work
*/
public class WorkerThread implements Runnable {
private List listeners = new ArrayList();
private List results;
public void run() {
// Do some long running work here
try {
// Sleep to simulate long running task
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
results = new ArrayList();
results.add("Result 1");
// Work done, notify listeners
notifyListeners();
}
private void notifyListeners() {
for (Iterator iter = listeners.iterator(); iter.hasNext();) {
WorkerListener listener = (WorkerListener) iter.next();
listener.workDone(this);
}
}
public void registerWorkerListener(WorkerListener listener) {
listeners.add(listener);
}
public List getResults() {
return results;
}
}
И наконец, основная программа, которая запускает рабочий поток и регистрирует слушателя, чтобы быть уведомленной однажды работа, сделана:
import java.util.Iterator;
import java.util.List;
/**
* Class to simulate a main program
*/
public class MainProg {
public MainProg() {
WorkerThread worker = new WorkerThread();
// Register anonymous listener class
worker.registerWorkerListener(new WorkerListener() {
public void workDone(WorkerThread thread) {
System.out.println("Work done");
List results = thread.getResults();
for (Iterator iter = results.iterator(); iter.hasNext();) {
String result = (String) iter.next();
System.out.println(result);
}
}
});
// Start the worker thread
Thread thread = new Thread(worker);
thread.start();
System.out.println("Main program started");
}
public static void main(String[] args) {
MainProg prog = new MainProg();
}
}
Опрос иначе активное ожидание не является хорошей идеей. Как Вы упомянули, активное ожидание тратит впустую циклы ЦП и может заставить Ваше приложение казаться безразличным.
Мой Java груб, но Вы хотите что-то как следующее:
Если один поток должен ожидать вывода другого потока, необходимо использовать условную переменную.
final Lock lock = new ReentrantLock();
final Condition cv = lock.newCondition();
Поток, заинтересованный выводом другой угрозы, должен звонить cv.wait()
. Это заставит текущий поток блокироваться. Когда рабочий поток закончен, работая, он должен звонить cv.signal()
. Это заставит заблокированный поток становиться разблокированным, позволяя этому осмотреть вывод рабочего потока.
Как альтернатива параллелизму API, как описано Saua (и если основной поток не должен знать, когда рабочий поток заканчивается) Вы могли использовать публиковать/подписывать шаблон.
В этом сценарии ребенок Thread
/Runnable
дан слушателя, который знает, как обработать результат и который призван обратно к когда ребенок Thread
/Runnable
завершается.
Поток подкласса, и дает Вашему классу метод, который возвращает результат. Когда метод называют, если результат не был создан, еще, то соединение () с Потоком. Когда соединение () возвраты, работа Вашего Потока будет сделана, и результат должен быть доступным; возвратите его.
Используйте это, только если на самом деле необходимо исчерпать асинхронное действие, сделайте некоторую работу, в то время как Вы ожидаете и затем получаете результат. Иначе, какой смысл Потока? Вы могли бы также просто записать класс, который делает работу и возвращает результат в основном потоке.
Другой подход был бы обратным вызовом: сделайте, чтобы Ваш конструктор взял аргумент, который реализует интерфейс с методом обратного вызова, который назовут, когда результат будет вычислен. Это сделает работу абсолютно асинхронной. Но если Вы во всей потребности ожидать результата в какой-то момент, я думаю, что Вы все еще испытываете необходимость для вызова соединения () от основного потока.
Как отмечено saua: используйте конструкции, предлагаемые java.util.concurrent. Если Вы застреваете с пред 1,5 (или 5.0), JRE, Вы, мог бы обратиться к виду прокрутки Вашего собственного, но Вы еще лучше из при помощи бэкпорта: http://backport-jsr166.sourceforge.net/