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

Все методы Thread (как getName/setName) потокобезопасны?

Можно ли использовать методы Thread, такие как setName/getName и некоторые другие из разных потоков? API ничего не говорит, но, судя по исходному коду

private char name[];

public final void setName(String name) {
    checkAccess();
    this.name = name.toCharArray();
}

public final String getName() {
    return String.valueOf(name);
}

похоже, что это может привести к ошибкам согласования памяти.

4b9b3361

Ответ 1

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

Хотя всегда было непонятно, почему Thread использует char[] для сохранения своего имени, вы поднимаете более важный вопрос, getName() явно неправильно синхронизирован. Если один поток имеет setName("abcd"), другой поток может наблюдать getName()->"ab\0\0".

Я отправлю вопрос в список concurrency -interest. см. http://cs.oswego.edu/pipermail/concurrency-interest/2013-March/010935.html

Ответ 2

"API ничего не говорит"

Если API ничего не говорит, вы никогда не можете предположить, что метод/класс является потокобезопасным. Как вы можете видеть из исходного кода, acess до name не является взаимным эксклюзивным.
Но для меня кажется, что name имеет либо старое значение, либо новое, ничего между ними, поэтому он выглядит безопасным для использования get/setName().

Ответ 3

Для начала, если один поток вызывает setName, а доступ к name не синхронизирован, нет гарантии, что любой другой поток будет когда-либо видеть это новое значение.

Во-вторых, String.valueOf(char[]) выполняет итерацию над name. Это означает, что если во время этой итерации задан хотя бы один из символов name, то итерационный поток может видеть несогласованные данные - первые символы исходного массива char и последние символы другого.

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

** EDIT **

Что касается второго небезопасного сценария, после прочтения этого вопроса и ответа, представляется гораздо менее очевидным, как реализована копия массива - это платформа -зависимая. Это объясняет, почему String,valueOf(char[]) не документируется как поточно-безопасный. Таким образом, во всяком случае, второй сценарий по-прежнему применяется как не потокобезопасный.

Ответ 4

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

Пример:

Thread t1 = new SomeThread(); t1.start();
(new MyThread(t1, new Runnable() { public void run() {t1.setName("HELLO");} })).start();
(new MyThread(t1, new Runnable() { public void run() {t1.setName("GOODBYE");} })).start();

Два потока, обращающиеся к одному объекту потока t1. Не безопасно.