LINUX.ORG.RU

for ArrayList и thread safety в Java

 


1

1

Скажем есть такой класс

class Test {
	private ArrayList<String> mList;
	
	Test() {
		mList = new ArrayList<String>();
		mList.add("Foo");
		mList.add("Bar");
		mList.add("Baz");
	}
	
	public ArrayList<String> search(String what) {
		ArrayList<String> res = new ArrayList<String>();
		
		for (String str : mList) {
			if (str.indexOf(what) != -1) {
				res.add(str);
			}
		}
		
		return res;
	}
}

Является ли метод search() потокобезопасным? А именно беспокоит одновременное итерирование по mList из разных потоков. Является ли эта операция безовасной при учёте того, что модификации mList не производится во время итерирования?

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

ma1uta ★★★ ()

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

maxcom ★★★★★ ()

Является ли метод search() потокобезопасным?

Да.

«список после заполнения был опубликован потокобезопасным способом»

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

str.indexOf(what) != -1

в java 1.5 есть contains

vtVitus ★★★★★ ()
Ответ на: комментарий от Olegymous

А что значит «список после заполнения был опубликован потокобезопасным способом»?

Это значит что твои треды перед использованием List'а должны взять указатель на него в synchronized блоке или из volatile переменной, или из final поля в которое была произведена запись после заполнения списка.

Например:

        private final ArrayList<String> mList;
	
	Test() {
		ArrayList<String> builder = new ArrayList<>();
		builder.add("Foo");
		builder.add("Bar");
		builder.add("Baz");
                mList = builder;
	}

почитай, например, http://stackoverflow.com/questions/801993/java-multi-threading-safe-publication

maxcom ★★★★★ ()
Ответ на: комментарий от vtVitus

В данном случае побоку, String, который хранится в контейнере, неизменяемый тип.

Это не так, так как сам контейнер - изменяемый тип. После его инициализации другие треды могут некоторое время видеть недоконструированный объект если не принять специальных мер чтобы этого небыло

maxcom ★★★★★ ()
Ответ на: комментарий от vtVitus

Можно так же попробовать использовать clone при создании результата поиска.

Clone не имеет какой-то мультитредовой семантики и не отменяет необходимость синхронизации

maxcom ★★★★★ ()

Если сможешь гарантировать, что завершение конструктора happens before вызовов search, то безопасно (например достаточно mList сделать final, тогда поле будет безопасно опубликовано). А что касается нескольких чтений, то они потокобезопасны. Условием возникновения гонки является несколько доступов, где хотя бы одним является запись, а тут только чтения.

dizza ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.