Подтвердить что ты не робот

Ограничение потока

Я читаю Java Concurrency на практике и немного путаюсь с концепцией ограничения потока. В книге говорится, что

Когда объект ограничен потоком, такое использование автоматически поточно-безопасно, даже если сам закрытый объект не является

Итак, когда объект ограничен потоком, ни один другой поток не может иметь к нему доступ? Это то, что значит ограничиться нитью? Как сохранить объект, ограниченный потоком?

Edit: Но что, если я все еще хочу поделиться объектом с другим потоком? Скажем, что после того, как поток A заканчивается с объектом O, поток B хочет получить доступ к O. В этом случае O все еще может быть привязан к B после того, как A будет выполнено с ним?

Использование локальной переменной - один из примеров, но это просто означает, что вы не делите свой объект с другим потоком (ВСЕ). В случае с пулом JDBC Connection он не передает одно соединение из одного потока в другой, как только поток выполняется с этим соединением (совершенно незнакомо об этом, потому что я никогда не использовал JDBC).

4b9b3361

Ответ 1

Итак, когда объект ограничен нитью, ни один другой поток не может иметь к нему доступ?

Нет, это наоборот: если вы убедитесь, что ни один другой поток не имеет доступа к объекту, то этот объект, как говорят, ограничен одним потоком.

Нет механизма языка или JVM-уровня, который ограничивает объект одним потоком. Вам просто нужно убедиться, что ссылка на объект не выйдет в место, к которому может обратиться другой поток. Существуют инструменты, которые помогают избежать утечки ссылок, таких как ThreadLocal, но ничего, что гарантирует, что ссылки отсутствуют просачивается где угодно.

Например: если ссылка только на объект принадлежит локальной переменной, то объект определенно ограничен одним потоком, так как другие потоки никогда не смогут получить доступ локальные переменные.

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

Редактирование объявлений: На практике у вас может быть объект, доступ к которому осуществляется только по одному потоку за время его жизни, но для которого этот единственный поток изменяется (объект JDBC Connection из пул соединений является хорошим примером).

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

И, на мой взгляд, эти объекты никогда не "ограничиваются одним потоком" (что будет означать сильную гарантию), но можно сказать, что "будет использоваться одним потоком только за один раз".

Ответ 2

Наиболее очевидным примером является использование локального хранилища потоков. См. Пример ниже:

class SomeClass {
    // This map needs to be thread-safe
    private static final Map<Thread,UnsafeStuff> map = new ConcurrentHashMap<>();

    void calledByMultipleThreads(){
        UnsafeStuff mystuff = map.get(Thread.currentThread());
        if (mystuff == null){
            map.put(Thread.currentThread(),new UnsafeStuff());
            return;
        }else{
            mystuff.modifySomeStuff();
        }
    }
}

Сами объекты UnsafeStuff "могут быть разделены" с другими потоками в том смысле, что если вы передадите какой-либо другой поток вместо Thread.currentThread() во время выполнения к методу map get, вы получите объекты, принадлежащие к другим потокам. Но вы не хотите этого делать. Это "использование, ограниченное потоком". Другими словами, условия выполнения таковы, что объекты фактически не разделяются между разными потоками.

С другой стороны, в приведенном ниже примере объект автоматически ограничивается потоком, и, так сказать, "сам объект" ограничен потоком. Это в том смысле, что невозможно получить ссылку из других потоков независимо от условий выполнения:

class SomeClass {
    void calledByMultipleThreads(){
        UnsafeStuff mystuff = new UnsafeStuff();
        mystuff.modifySomeStuff();
        System.out.println(mystuff.toString());
    }
}

Здесь UnsafeStuff выделяется внутри метода и выходит из области действия при возврате метода. Другими словами, спецификация Java обеспечивает статически, чтобы объект всегда ограничивался одним потоком. Таким образом, это не условие выполнения или способ его использования, который обеспечивает ограничение, а скорее спецификацию Java.

Фактически, современные JVM иногда выделяют такие объекты в стеке, в отличие от первого примера (лично не проверяли это, но я не думаю, что по крайней мере текущие JVM).

Иными словами, в первом примере JVM не может быть уверен, что объект ограничен внутри потока, просто просматривая calledByMultipleThreads() (кто знает, что другие методы возились с SomeClass.map). В последнем примере это возможно.


Изменить: Но что, если я все еще хочу поделиться объектом с другим потоком? Скажем, что после окончания резьбы A с объектом O, поток B хочет доступ O. В этом случае, возможно, O все еще ограниченный B после того, как A сделано с ним?

Я не думаю, что в этом случае он называется "ограниченным". Когда вы это делаете, вы просто гарантируете, что объект не будет доступен одновременно. Так работает EJB concurrency. Вы все равно должны "безопасно публиковать" рассматриваемый общий объект в потоках.

Ответ 3

Я предполагаю, что хочу сказать. Как создание объекта внутри метода run, а не передача ссылки на любой другой экземпляр.

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

public String s;

public void run() {
  StringBuilder sb = new StringBuilder();
  sb.append("Hello ").append("world");
  s = sb.toString();
}

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

Ответ 4

Итак, когда объект ограничен потоком, ни один другой поток не может иметь к нему доступ?

То, что означает ограничение потока - к объекту можно получить доступ только к одному потоку.

Это то, что значит ограничиться нитью?

См. выше.

Как сохранить объект, ограниченный потоком?

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

  • вы создаете новый объект и
  • вы никогда не назначаете ссылку на объект для переменной экземпляра или класса, а
  • вы никогда не вызываете метод, который делает это для ссылки,
  • тогда объект будет ограничен потоком.

Ответ 5

Одним из способов является "удержание стека", в котором объектом является локальная переменная, ограниченная стеком потоков, поэтому ни один другой поток не может получить к ней доступ. В нижеприведенном методе list является локальной переменной и не выходит из метода. Список не должен быть потокобезопасным, поскольку он ограничен стеком исполняемых потоков. Ни одна другая нить не может ее изменить.

public String foo(Item i, Item j){
    List<Item> list = new ArrayList<Item>();
    list.add(i);
    list.add(j);
    return list.toString();
}

Другим способом ограничить объект потоком является использование переменной ThreadLocal, которая позволяет каждому потоку иметь свою собственную копию. В приведенном ниже примере каждый поток будет иметь свой собственный объект DateFormat, поэтому вам не нужно беспокоиться о том, что DateFormat не является потокобезопасным, поскольку к нему не будут доступны несколько потоков.

private static final ThreadLocal<DateFormat> df
                 = new ThreadLocal<DateFormat>(){
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyyMMdd");
    }
  };

Дополнительная литература

Ответ 6

Смотрите: http://codeidol.com/java/java-concurrency/Sharing-Objects/Thread-Confinement/

Более формальные средства поддержания ограничение потока - это ThreadLocal, который позволяет вам связать значение для каждой строки с сохранением значения объект. Thread-Local обеспечивает получение и установить методы доступа, которые поддерживают отдельная копия значения для каждого который использует его, поэтому get возвращает последнее значение, переданное в набор из текущего исполняемого потока.

Он содержит копию объекта за один поток, поток A не может получить доступ к копии потока B и сломал его инварианты, если вы сделаете это специально (например, присвойте значение ThreadLocal статической переменной или выложите ее с помощью других методов)

Ответ 7

Что именно это означает. К самому объекту обращается только один поток и, следовательно, поточно-безопасен. ThreadLocal объекты - это объекты, привязанные к единственному потоку

Ответ 8

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

Если это так, объект не должен быть "потокобезопасным"