Это правильный способ считать в многопоточности?

1

Я хочу получить все значения из класса 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;
    }
}
Теги:
multithreading

1 ответ

1
Лучший ответ

Синхронизация кажется мне верной. Если подсчет является вашей единственной задачей, вы можете пропустить класс 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, раздел "Примеры использования".

  • 1
    Хотя непосредственное переключение на AtomicInteger может упростить код в этом конкретном примере, я определенно не рекомендовал бы это в качестве общего подхода. Наличие класса Counter позволяет вам добавлять другие функции, например, обратные вызовы и уведомления о прогрессе, когда значение изменяется, и возможность ждать, пока счетчик не достигнет определенного значения (и возможность переключаться на другие реализации в зависимости от требований, например, Semaphore или CountDownLatch и т. д.). Один только AtomicInteger не имеет особой функциональности.
  • 1
    Я согласен. Но в этом конкретном примере класс Counter делает код намного более сложным и отвлекает от основного вопроса о синхронизации. Тем не менее я обновлю свой ответ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню