Java 6 Потоковый вывод не асинхронный? - PullRequest
1 голос
/ 23 июля 2010

Этот код должен выдавать четные и неровные выходные данные, потому что не синхронизируется ни с какими методами.Тем не менее, выход на моей JVM всегда четный.Я действительно запутался, поскольку этот пример исходит прямо из Дуга Ли.

public class TestMethod implements Runnable {

private int index = 0;

    public void testThisMethod() {
        index++;
        index++;
        System.out.println(Thread.currentThread().toString() + " "
                    + index );

    }

    public void run() {
        while(true) {
            this.testThisMethod();
        }
    }

    public static void main(String args[]) {
        int i = 0;
        TestMethod method = new TestMethod();
        while(i < 20) {
            new Thread(method).start();
            i++;
        }
    }
}

Вывод

Тема [Тема 8,5, главная] 135134

Тема [Тема-8,5, основная] 135136

Тема [Тема-8,5, основная] 135138

Тема [Тема-8,5, основная] 135140

Тема [Нить-8,5, основная] 135142

Нить [Нить-8,5, основная] 135144

Ответы [ 6 ]

4 голосов
/ 23 июля 2010

Я попытался с volatile и получил следующее (с if для печати, только если нечетное):

Thread[Thread-12,5,main] 122229779
Thread[Thread-12,5,main] 122229781
Thread[Thread-12,5,main] 122229783
Thread[Thread-12,5,main] 122229785
Thread[Thread-12,5,main] 122229787

Ответ на комментарий:

индекс используется совместно, потому что у нас есть один TestMethod экземпляр, но много Thread s, которые вызывают testThisMethod() на одном TestMethod, который у нас есть.


Код (без изменений, кроме упомянутых выше):

public class TestMethod implements Runnable {

    volatile private int index = 0;

        public void testThisMethod() {
            index++;
            index++;
            if(index % 2 != 0){
            System.out.println(Thread.currentThread().toString() + " "
                        + index );
            }

        }

        public void run() {
            while(true) {
                this.testThisMethod();
            }
        }

        public static void main(String args[]) {
            int i = 0;
            TestMethod method = new TestMethod();
            while(i < 20) {
                new Thread(method).start();
                i++;
            }
        }
    }
3 голосов
/ 23 июля 2010

Прежде всего: как уже отмечали другие, нет никакой гарантии, что ваши потоки прерываются между двумя операциями приращения.

Обратите внимание, что печать в System.out весьма вероятно вызывает некоторую синхронизацию в ваших потоках, поэтому ваши потоки, скорее всего, только что начали отрезок времени, когда они вернутся из этого, поэтому они, вероятно, завершат две операции приращения затем дождитесь общего ресурса для System.out.

Попробуйте заменить System.out.println() на что-то вроде этого:

int snapshot = index;
if (snapshot % 2 != 0) {
  System.out.println("Oh noes! " + snapshot);
}
3 голосов
/ 23 июля 2010

Результат точно такой, как я ожидал.Индекс увеличивается вдвое между выходами, и нет никакого взаимодействия между потоками.

Чтобы перевернуть вопрос - зачем ожидать нечетные результаты?

РЕДАКТИРОВАТЬ: К сожалению.Я ошибочно предположил, что для каждого потока создавался новый runnable, и поэтому для каждого потока был отдельный индекс, а не общий.Тревожно, как такой ошибочный ответ получил 3 голосов, хотя ...

3 голосов
/ 23 июля 2010

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

Дело в том, что даже если вы исправите проблемы, упомянутые в других ответах, вы все равно не сможете рассчитывать на то, что вещи выходят определенным образом;вы всегда должны быть готовы к любому возможному чередованию, которое допускает модель памяти и потоков Java, и это включает в себя возможность того, что println всегда происходит после четного числа приращений, даже если это кажется маловероятно для вас.

0 голосов
/ 23 июля 2010

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

То есть вы должны Thread.sleep () или (не рекомендуется) Thread.yield () в цикле.

0 голосов
/ 23 июля 2010

Вы не отметили index как изменчивое. Это означает, что компилятору разрешено оптимизировать доступ к нему, и он, вероятно, объединяет ваши 2 приращения в одно добавление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...