Параллелизм, объектная видимость

Используя __init__.py файл позволяет Вам делать внутреннюю структуру пакета невидимой из внешней стороны. Если внутренняя структура изменяется (например, потому что Вы разделяете один толстый модуль на два), только необходимо корректироваться __init__.py файл, но не код, который зависит от пакета. Можно также сделать части пакета невидимыми, например, если они не готовы к общему использованию.

Примечание, которое можно использовать эти del команда, таким образом, типичное __init__.py может быть похожим на это:

from somemodule import some_function1, some_function2, SomeObject

del somemodule

Теперь, если Вы решаете разделить somemodule, новое __init__.py могло бы быть:

from somemodule1 import some_function1, some_function2
from somemodule2 import SomeObject

del somemodule1
del somemodule2

С внешней стороны пакет все еще смотрит точно как прежде.

7
задан Integer 30 December 2009 в 04:55
поделиться

6 ответов

Да, это безопасно, даже если исполнитель заменил свой поток посередине. Начало / завершение потока также являются точками синхронизации.

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4

Простой пример:

static int state;
static public void main(String... args) {
    state = 0;                   // (1)
    Thread t = new Thread() {
        public void run() {
            state = state + 1;   // (2) 
        }
    };
    t.start();
    t.join();
    System.out.println(state);  // (3)
}

Это Гарантируется, что (1), (2), (3) хорошо упорядочены и ведут себя так, как ожидалось.

Для однопоточного исполнителя «Задачи гарантированно выполняются последовательно», он должен каким-то образом определять завершение одной задачи перед запуск следующего, который обязательно правильно синхронизирует разные run ()

2
ответ дан 7 December 2019 в 05:24
поделиться

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

public void run() {
    synchronize (this) {
        if (this.state != -1)
            this.state++;
    }
}

Вместо использования синхронизации вы также можете использовать AtomicInteger # getAndIncrement () (если раньше вам не понадобился if).

private AtomicInteger state = new AtomicInteger();

public void run() {
    state.getAndIncrement()
}
4
ответ дан 7 December 2019 в 05:24
поделиться

Ваш код, в частности этот бит

            if (this.state != -1)
                    this.state++;

, потребует атомарной проверки значения состояния, а затем приращения к состоянию в параллельном контексте. Таким образом, даже если ваша переменная была изменчивой и задействовано более одного потока, у вас были бы проблемы с параллелизмом.

Но ваш дизайн основан на утверждении, что всегда будет только один экземпляр Test, и , этот единственный экземпляр предоставляется только одному (тому же) потоку. (Но обратите внимание, что единственный экземпляр на самом деле является общим состоянием между основным потоком и потоком-исполнителем.)

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

0
ответ дан 7 December 2019 в 05:24
поделиться

Если ваш ExecutorService является однопоточным, то общего состояния нет, поэтому я не понимаю, как здесь могут быть какие-то проблемы.

Однако не было бы больше смысла в передавать новый экземпляр вашего класса Test каждому вызову execute () ? т.е.

for (int i=0; i<10; ++i)
    ex.execute(new Test());

Таким образом, общего состояния не будет.

-1
ответ дан 7 December 2019 в 05:24
поделиться

Изначально я думал так:

Если бы задача всегда выполнялась той же нити, не было бы проблема. Но Excecutor произведено newSingleThreadExecutor () может создавать новые потоки, чтобы заменить те, которые убиты по любой причине. Здесь нет гарантия о том, когда замена поток будет создан или какой поток создаст его.

Если поток выполняет некоторые записи, то вызывает start () в новом потоке, те записи будут видны новым нить. Но нет никакой гарантии, что это правило применимо и в данном случае.

Но неоспоримое право: создание правильного ExecutorService без достаточных барьеров для обеспечения видимости практически невозможно. Я забыл, что обнаружение смерти другого потока - это связь синхронизируется с . Механизм блокировки, используемый для простоя рабочих потоков, также потребует барьера.

3
ответ дан 7 December 2019 в 05:24
поделиться

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

Однако, если вы хотите использовать значение состояния в основном потоке, который запускает цикл, вы должны сделать поле изменчивым :

    for (int i=0; i<10; ++i) {
            ex.execute(test);
            System.out.println(test.getState());
    }

Однако даже это может работать некорректно с volatile, потому что нет синхронизации между потоками.

Поскольку поле является частным, проблема возникает только в том случае, если основной поток выполняет метод, который может получить доступ к этому полю .

0
ответ дан 7 December 2019 в 05:24
поделиться