Я хочу получить все значения из класса WorkerThread после завершения 5 потоков. Как работает счетчик? Благодарю. В конструкторе WorkerThread кажется, что каждый счетчик становится одной переменной каждого потока, не разделяемой между 5 потоками.
public class Test {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
Counter counter = new Counter();
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread(String.valueOf(i), counter);
executor.execute(worker);
}
executor.shutdown();
System.out.println("Total Count: " + counter.value());
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
}
}
class Counter{
private AtomicInteger count;
public Counter(){
count = new AtomicInteger();
}
public int increment(){
return count.incrementAndGet();
}
public int value(){
return count.get();
}
}
class WorkerThread implements Runnable {
private String command;
private Counter c;
public WorkerThread(String s, Counter c){
this.command=s;
this.c = c;
}
@Override
public void run() {
for(int i=0; i<6; i++){
c.increment();
}
processCommand();
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString(){
return this.command;
}
}
Синхронизация кажется мне верной. Если подсчет является вашей единственной задачей, вы можете пропустить класс Counter и напрямую использовать AtomicInteger для удаления сложности. (Держите его, если вы хотите реализовать более сложные задачи, для которых требуется соответствующий синхронизированный объект общего состояния).
Не называйте свой рабочий класс "Thread". Это не поток, это задача, выполняемая потоком.
И последнее, но не менее важное: что-то не так с вашим кодом выключения. Обратите внимание, что выключение не блокируется, а немедленно возвращается. Поэтому вы слишком рано оцениваете свой счетчик.
Следующий код устраняет все эти проблемы:
public class Test {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
AtomicInteger counter = new AtomicInteger();
for (int i = 0; i < 10; i++) {
executor.execute(new Worker(counter));
}
executor.shutdown();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
// executor does not shut down.
// try executor.shutdownNow() etc.
}
System.out.println("Total Count: " + counter.get());
}
}
class Worker implements Runnable {
private final AtomicInteger counter;
public Worker(AtomicInteger counter) {
this.counter = counter;
}
public void run() {
// do something
counter.incrementAndGet();
// do something else
}
}
Для получения дополнительной информации о том, как правильно завершить работу ExecutorService
, см. Http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html, раздел "Примеры использования".
AtomicInteger
может упростить код в этом конкретном примере, я определенно не рекомендовал бы это в качестве общего подхода. Наличие классаCounter
позволяет вам добавлять другие функции, например, обратные вызовы и уведомления о прогрессе, когда значение изменяется, и возможность ждать, пока счетчик не достигнет определенного значения (и возможность переключаться на другие реализации в зависимости от требований, например,Semaphore
илиCountDownLatch
и т. д.). Один толькоAtomicInteger
не имеет особой функциональности.