Вести счетчик с ExecutorService?

Я хотел бы сохранить счетчик выполненных потоков, чтобы использовать в тех же потоках, которые я выполняю.

Проблема здесь в том, что, хотя счетчик увеличивается, он увеличивается неравномерно, и из вывода консоли я получил это (у меня есть цикл for, который выполняет 5 потоков с ExecutorService):

This is a test. N:3
This is a test. N:4
This is a test. N:4
This is a test. N:4
This is a test. N:4

Как вы можете видеть вместо получения 1,2,3,4,5 я получил 3,4,4,4,4,

Я предполагаю, что это связано с тем, что цикл for выполняется достаточно быстро, чтобы выполнять потоки, а потоки - достаточно быстро, чтобы выполнить код, запрашивающий счетчик, быстрее, чем счетчик может обновиться сам (имеет ли это смысл?).

Вот код (он меньше и не имеет смысла для счетчика):

for (int i = 0; i  <  5; i++)
{

Thread thread;
thread = new Thread()
    {

        public void run()
            {



                System.out.println("This is test. N: "+aldo );
                //In here there is much more stuff, saying it because it might slow down the execution (if that is the culprit?)
                return;
            }
    };

threadList.add(thread);
}
//later
for (int i = 0; i < threadList.size(); i++)
{

executor.execute(threadList.get(i));
aldo = aldo + 1;

}
executor.shutdown();
try
{
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e)
{

}

Да, aldo счетчик (с несколькими другими списками, я думаю) отсутствует в коде (они очень просты).

2 ответа

Решение

Лучший способ сделать это - создать собственный класс потока с конструктором, который передает число. Переменная, содержащая номер, может быть использована позже для любой необходимой регистрации. Вот код, который я придумал.

public static void main(String[] args) {
    class NumberedThread implements Runnable {
        private final int number;
        public NumberedThread(int number) {
            this.number = number;
        }

        @Override
        public void run() {
            System.out.println("This is test. N: " + number);
        }
    }

    List<Thread> threadList = new ArrayList<>();
    for (int i = 1; i  <  6; i++) threadList.add(new Thread(new NumberedThread(i)));

    ExecutorService executor = Executors.newFixedThreadPool(10);;
    for (Thread thread : threadList) executor.execute(thread);
    executor.shutdown();
    try {
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    }
    catch (InterruptedException ignored) { }
}

Вместо этого вы также можете использовать строковый объект, если хотите назвать имена потоков.

aldo не изменяется задачами в потоке, но вместо этого изменяется в основном потоке, здесь:

for (int i = 0; i < threadList.size(); i++) {
    executor.execute(threadList.get(i));
    //here...
    aldo = aldo + 1;
}

Кроме того, поскольку вы хотите счетчик, который может увеличить свое значение в нескольких потоках, вы можете использовать AtomicInteger скорее, чем int,

Ваш код должен выглядеть так:

AtomicInteger aldo = new AtomicInteger(1);

for (int i = 0; i < 5; i++) {
    executor.execute( () -> {
        System.out.println("This is test. N: " + aldo.getAndIncrement());
    });
}
Другие вопросы по тегам