powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / codereview самописный потокобезопасный stack
120 сообщений из 120, показаны все 5 страниц
codereview самописный потокобезопасный stack
    #39399496
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
public interface MyNonBlockingStack<T> {
    void put(T t) throws InterruptedException;

    T poll() throws InterruptedException;
}

class MyNonBlockingStackImpl<T> implements MyNonBlockingStack<T> {

    private Object internalMonitor = new Object();
    private List<T> list = new ArrayList<>();
    private int maxSize;

    public MyNonBlockingStackImpl(int maxSize) {
        this.maxSize = maxSize;
    }

    @Override
    public synchronized void put(T t) throws InterruptedException {
        while (maxSize <= list.size()) {
            System.out.println("wait put by " + Thread.currentThread().getId());
            wait();
            System.out.println("wait put by " + Thread.currentThread().getId());

        }
        list.add(t);
        notify();

    }

    @Override
    public synchronized T poll() throws InterruptedException {
        while (list.size() == 0) {
            System.out.println("wait read by " + Thread.currentThread().getId());
            wait();
            System.out.println("woken up read by " + Thread.currentThread().getId());

        }
        T t = list.get(list.size()-1);
        list.remove(t);
        notify();
        return t;
    }
}
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399497
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
сорри
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
class MyNonBlockingStackImpl<T> implements MyNonBlockingStack<T> {

    private List<T> list = new ArrayList<>();
    private int maxSize;

    public MyNonBlockingStackImpl(int maxSize) {
        this.maxSize = maxSize;
    }

    @Override
    public synchronized void put(T t) throws InterruptedException {
        while (maxSize <= list.size()) {
            wait();
        }
        list.add(t);
        notify();

    }

    @Override
    public synchronized T poll() throws InterruptedException {
        while (list.size() == 0) {
            wait();
        }
        T t = list.get(list.size()-1);
        list.remove(t);
        notify();
        return t;
    }
}
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399514
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И... В чем смысл топика?

Да и вообще, приведенный Вами код работает? Что мне он кажется _ну_крайне_ странным.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399527
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Leonid KudryavtsevИ... В чем смысл топика?

Да и вообще, приведенный Вами код работает? Что мне он кажется _ну_крайне_ странным.

потренироваться писать многопоточный код)

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
class Main {
    public static void main(String[] args) throws InterruptedException {
        MyNonBlockingStackImpl<Integer> myNonBlockingStack = new MyNonBlockingStackImpl<>(5);

        for (int i = 0; i < 10; i++) {
            final int currentValue = i;
            //writer
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        myNonBlockingStack.put(currentValue);
                        //System.out.println("Put " + currentValue + " by " + Thread.currentThread().getId());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        Thread.sleep(5000);
        for (int i = 0; i < 10; i++) {
            //reader
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // System.out.println("Read " +
                        myNonBlockingStack.poll();
                        //         + " by " + Thread.currentThread().getId());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            Thread.sleep(10);
        }

    }
}



я добавил логов и вроде всё работает. только он конечно blocking, название кривое.

Собсно с учетом отсутвия опыта написания многопоточнго кода в продакшене и возникла мысль показать что есть тут. Вдруг будет аргументированная критика.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399532
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Код: java
1.
public synchronized

а как же тонкая оптимизация с использованием volatile -переменных?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399535
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Usmanquestioner
Код: java
1.
public synchronized

а как же тонкая оптимизация с использованием volatile -переменных?

Ок, попробую написать ещё и неблокирующий алгоритм.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399539
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я только не понял, нафига там куча wait и notify. Нафига оно надо и что оно должно было делать.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399546
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Leonid KudryavtsevЯ только не понял, нафига там куча wait и notify. Нафига оно надо и что оно должно было делать.

1. Чтобы поток подвис до появления значения в очереди пока она пустая
2. Если очередь переполнена, то ждём пока освободится место
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399550
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner1. Чтобы поток подвис до появления значения в очереди пока она пустая
2. Если очередь переполнена, то ждём пока освободится место


Leonid KudryavtsevДа и вообще, приведенный Вами код работает? Что-то мне он кажется _ну_крайне_ странным.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399552
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Leonid Kudryavtsev,

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
class Main {
    public static void main(String[] args) throws InterruptedException {
        BlockingConcurrentStack<Integer> myNonBlockingStack = new BlockingConcurrentStack<>(5);

        for (int i = 0; i < 10; i++) {
            final int currentValue = i;
            //writer
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        myNonBlockingStack.put(currentValue);
                        //System.out.println("Put " + currentValue + " by " + Thread.currentThread().getId());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        Thread.sleep(5000);
        for (int i = 0; i < 10; i++) {
            //reader
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // System.out.println("Read " +
                        myNonBlockingStack.poll();
                        //         + " by " + Thread.currentThread().getId());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            Thread.sleep(10);
        }

    }
}



можете запустить.

Но конечно это не значит, что код всегда корректно работает.

А что конкретно не нравится то? а то без аргументов хейтить это неконструктивно
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399553
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
1. Конструктор не thread safe
2. Сочетание NonBlocking и IterruptedException в интерфейсе это прикольно :o)
3. Ну и вообще с synchronized не интересно
4. Как уже заметили, это самый что ни на есть blocking
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399564
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На мой IMHO приведенный Вами код stack'а совершенно "странный"
Ваш код который его "проверяет" еще более страннее.

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

Т.ч., что тут критиковать, я даже не знаю.

questionerможете запустить.

Не собираюсь. Банально лениво. Всякий мусор на компьютере запускать.

Да и зачем? Где тут многопоточное выполнение? Что этот код делает?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399569
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid KudryavtsevГде тут многопоточное выполнение?
А не, беру свои слова обратно. "Многопоточность" тут конечно есть, частично. Но именно, что частично.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399571
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Leonid KudryavtsevНа мой IMHO приведенный Вами код stack'а совершенно "странный"
Ваш код который его "проверяет" еще более страннее.

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

Т.ч., что тут критиковать, я даже не знаю.

questionerможете запустить.

Не собираюсь. Банально лениво. Всякий мусор на компьютере запускать.

Да и зачем? Где тут многопоточное выполнение? Что этот код делает?

складывается впечатление, что Вам просто поворчать не на кого)

или четко выразить свою мысли Вы не можете.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399575
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no568921. Конструктор не thread safe
2. Сочетание NonBlocking и IterruptedException в интерфейсе это прикольно :o)
3. Ну и вообще с synchronized не интересно
4. Как уже заметили, это самый что ни на есть blocking


Вот это аргументированная критика.

no568921. Конструктор не thread safe
что конкретно не так с конструктором? какие проблемы могут быть?

мне кажется synchronized даёт все необходимые гарантии
no568922. Сочетание NonBlocking и IterruptedException в интерфейсе это прикольно :o)

всё-таки это Blocking конечно
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399576
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Leonid Kudryavtsev,

Ну тут можно юзать ReadWriteLock явно, но мне это уже неинтересно.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399581
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Чтобы не было разночтений с именами - последняя версия:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
public interface ConcurrentStack<T> {
    void put(T t) throws InterruptedException;

    T poll() throws InterruptedException;
}

class BlockingConcurrentStack<T> implements ConcurrentStack<T> {

    private List<T> list = new ArrayList<>();
    private int maxSize;

    public BlockingConcurrentStack(int maxSize) {
        this.maxSize = maxSize;
    }

    @Override
    public synchronized void put(T t) throws InterruptedException {
        while (maxSize <= list.size()) {
            //System.out.println("wait Put " + t + " by " + Thread.currentThread().getId());
            wait();
        }
        list.add(t);
        System.out.println("Put " + t + " by " + Thread.currentThread().getId());
        notify();

    }

    @Override
    public synchronized T poll() throws InterruptedException {
        while (list.size() == 0) {
            //System.out.println("wait poll " + " by " + Thread.currentThread().getId());
            wait();
        }
        T t = list.get(list.size() - 1);
        list.remove(t);
        System.out.println("Read " + t + " by " + Thread.currentThread().getId());
        notify();
        return t;
    }
}
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399584
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerили четко выразить свою мысли Вы не можете.
Выражаюсь четче. На мой взгляд, "Многопоточность" это ОДНОВРЕМЕННОЕ выполнение какого либо кода

Если уж Вы пишите проверку для своей поделки, то хорошо, было бы, если бы она "многопоточность" и проверяла. Особенно, если Вы уверяете:
1. Чтобы поток подвис до появления значения в очереди пока она пустая
2. Если очередь переполнена, то ждём пока освободится место


В общем, проверьте ситуацию, когда один поток вставляет данные, а другой ОДНОВРЕМЕННО их оттуда считывает. Да при этом, что бы и проявлялась ситуация описанная Вами же. Пока, наблюдается совершенно странный полуторно-поточный тестовый код.

ПОСЛЕДОВАТЕЛЬНО:
1. Добавляющий данные в коллекцию (тут правда, хоть что-то многопоточное присудствует)
2. ПОСЛЕДОВАТЕЛЬНО (т.к. Вы зачем-то sleep внутрь цикла вставили) считывающий данные из коллекции.

На что встречный вопрос: где в Вашем коде проверки хоть какая-то адекватная многопоточность? И что тут можно обсуждать?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399588
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Leonid Kudryavtsev,

такой вариант я тоже проверял, работает. последний раз немного модифицировал код, чтобы удостовериться, что если очередь переполнена, то значения никуда не пропадают
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399593
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Кстати неблокирующий вариант возможен с обычным List ?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399609
Partisan M
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По моим наблюдениям это самая вредная ошибка плохих программистов. Не то, что они программируют плохо, а что они программируют то, что не надо программировать. Обсуждать тут нечего.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399620
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerКстати неблокирующий вариант возможен с обычным List ?
Код: java
1.
List list = Collections.synchronizedList(...);
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399648
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Насчет wait/notify, это я ошибся. Сорри.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399674
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Partisan MПо моим наблюдениям это самая вредная ошибка плохих программистов. Не то, что они программируют плохо, а что они программируют то, что не надо программировать. Обсуждать тут нечего.
Это задание просто потренироваться. Говорю же нет опыта написания в проде многопоточнго кода.


Я пишу это не потому, что мне очередь нужна, а потому, что мне нужен навык.


Можете предложить и другие задания, если они будут лучше я только рад.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399702
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
UsmanquestionerКстати неблокирующий вариант возможен с обычным List ?
Код: java
1.
List list = Collections.synchronizedList(...);



ну а что если так:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
    volatile AtomicBoolean isReading = new AtomicBoolean(false);
    volatile AtomicBoolean isWriting = new AtomicBoolean(false);

    @Override // non-blocking
    public boolean offer(T t) {
        if (isReading.compareAndSet(false, true)) {
            if (isWriting.compareAndSet(false, true)) {

                if (list.size() >= maxSize) {
                    return false;
                }
                boolean addResult = list.add(t);
                isWriting.set(false);
                isReading.set(false);
                return addResult;
            }
            isReading.set(false);
        }
        return false;
    }

    @Override // non-blocking
    public T take() {
        if (isReading.compareAndSet(false, true)) {
            T t = list.get(list.size() - 1);
            isReading.set(false);
            return t;
        }
        return null;
    }
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399703
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
хотя это всё равно не позволит несколько читателей сразу... надо ещё подумать
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399704
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторчто конкретно не так с конструктором? какие проблемы могут быть?

мне кажется synchronized даёт все необходимые гарантии
А где у вас hb между вызовом конструктора и вызовом методов pop/push...? В предыдущей теме столько обсуждали...
Еще добавлю про Ваш код - обычно размер стека динамический, т.е. заранее не задается, в таком случае нафига мьютекс на запись? Ок, мы оставляем синхронайзд только для notify, но тут проблема - у нас то, где хранятся элементы совсем не конкаррент. Поэтому я бы сделал так:
Вот это lock-free стэк:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
class ConcurrentStack<E> {
	
	private final AtomicReference<Entry<E>> pointer = new AtomicReference<>();
	
	public void push(E element) {
		boolean finish = false;
		do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = new Entry<>(element, currentTop);
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
	}
	
	public E pop() {
		E ret = null;
		boolean finish = false;
		do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = null;
			if(currentTop != null) {
				ret = currentTop.element;	
				newTop = currentTop.prev;
			}
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
		return ret;
	}
	
	private static class Entry<E> {
		final E element; 
		final Entry<E> prev; 
		//здесь файналы не обязательны строго говоря, но так best practice (у нас hb //создает запись/чтение pointer

		Entry(E element, Entry<E> prev) {
			this.element = element;
			this.prev = prev;
		}
	}
}


А вот так - тот BlockingStack, который Вам и нужен:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
class BlockingStack<E> {
	
	final private ConcurrentStack<E> concurrentStack = new ConcurrentStack<E>();
	final private Semaphore blockStuff = new Semaphore(0);
	
	public void push(E element) {
		concurrentStack.push(element);
		blockStuff.release();
	}
	
	public E pop() throws InterruptedException {
		blockStuff.acquire();
		return concurrentStack.pop();
	}
}


questioner, Вам вот задание (ну Вы же сами просили) - написать метод size() для ConcurrentStack.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399706
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Чего-то я тупанул, всё оба действия ведь модифицируют коллекцию, соответственно 2 потока одновременно не могут производить операции

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
 volatile AtomicBoolean locked = new AtomicBoolean(false);

    @Override
    public boolean offer(T t) {
        if (locked.compareAndSet(false, true)) {

            if (list.size() >= maxSize) {
                return false;
            }
            boolean addResult = list.add(t);
            locked.set(false);
            return addResult;
        }
        return false;
    }

    @Override
    public T take() {
        if (locked.compareAndSet(false, true)) {
            T t = list.get(list.size() - 1);
            locked.set(false);
            return t;
        }
        return null;
    }
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399712
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
вот такой вариант наверное будет работать, но медленно:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
public interface ConcurrentStack<T> {
    //blocking
    void put(T t) throws InterruptedException;

    //blocking
    T poll() throws InterruptedException;

    //non-blocking put
    boolean offer(T t);

    //non-blocking get
    T take();
}

class ConcurrentStackImpl<T> implements ConcurrentStack<T> {
    private volatile AtomicBoolean locked = new AtomicBoolean(false);
    private List<T> internalList = new ArrayList<T>();
    private final int maxSize;

    public ConcurrentStackImpl(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException();
        }
        this.maxSize = maxSize;
    }

    @Override //blocking
    public void put(T t) throws InterruptedException {
        while (!locked.compareAndSet(false, true)) ;//busy waiting
        internalList.add(t);
        locked.set(false);
    }

    @Override // non-blocking
    public T poll() throws InterruptedException {
        while (!locked.compareAndSet(false, true)) ;//busy waiting
        T value = internalList.get(internalList.size() - 1);
        locked.set(false);
        return value;
    }

    @Override
    public boolean offer(T t) {
        if (locked.compareAndSet(false, true)) {

            if (internalList.size() >= maxSize) {
                return false;
            }
            boolean addResult = internalList.add(t);
            locked.set(false);
            return addResult;
        }
        return false;
    }

    @Override
    public T take() {
        if (locked.compareAndSet(false, true)) {
            T t = internalList.get(internalList.size() - 1);
            locked.set(false);
            return t;
        }
        return null;
    }

}
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399716
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no56892
Еще добавлю про Ваш код - обычно размер стека динамический, т.е. заранее не задается, в таком случае нафига мьютекс на запись? Ок, мы оставляем синхронайзд только для notify, но тут проблема - у нас то, где хранятся элементы совсем не конкаррент.


Не понял причинно-следственной связи. мы оставляем synchronized дабы исключить параллельное изменение коллекции потоками.
no56892 Поэтому я бы сделал так:
Вот это lock-free стэк:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
class ConcurrentStack<E> {
	
	private final AtomicReference<Entry<E>> pointer = new AtomicReference<>();
	
	public void push(E element) {
		boolean finish = false;
		do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = new Entry<>(element, currentTop);
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
	}
	
	public E pop() {
		E ret = null;
		boolean finish = false;
		do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = null;
			if(currentTop != null) {
				ret = currentTop.element;	
				newTop = currentTop.prev;
			}
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
		return ret;
	}
	
	private static class Entry<E> {
		final E element; 
		final Entry<E> prev; 
		//здесь файналы не обязательны строго говоря, но так best practice (у нас hb //создает запись/чтение pointer

		Entry(E element, Entry<E> prev) {
			this.element = element;
			this.prev = prev;
		}
	}
}




Вроде да, должно работать, но по-моему это то же самое, что я написал(спору нет, после Вас).

А вот так - тот BlockingStack, который Вам и нужен:
no56892
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
class BlockingStack<E> {
	
	final private ConcurrentStack<E> concurrentStack = new ConcurrentStack<E>();
	final private Semaphore blockStuff = new Semaphore(0);
	
	public void push(E element) {
		concurrentStack.push(element);
		blockStuff.release();
	}
	
	public E pop() throws InterruptedException {
		blockStuff.acquire();
		return concurrentStack.pop();
	}
}




я не понял идею. явно где-то не хватает semaphore.take()

авторquestioner, Вам вот задание (ну Вы же сами просили) - написать метод size() для ConcurrentStack.[/quote]

Судя по всему надо, чтобы никто не работал в этот момент. Сейчас придумаю
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399720
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ну и кстати концептуальный вопрос ещё:

конструкция вида:
Код: java
1.
2.
3.
4.
do{
  oldState = atom.get();//1
 //some sork
}while(atom.compareAndSet(oldState, newState))

//2

Как я понимаю мы пытаемся симулировать ситуацию, что между //1 и //2 никаких действий не произошло.

Но ведь за это время мог элемент добавиться и удалиться, а в итоге состояние то же с точки зрения нашей проверки.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399721
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Но ведь за это время мог элемент добавиться и удалиться, а в итоге состояние то же с точки зрения нашей проверки.

Гугли по ключевым словам проблема ABA
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399723
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никquestionerНо ведь за это время мог элемент добавиться и удалиться, а в итоге состояние то же с точки зрения нашей проверки.

Гугли по ключевым словам проблема ABA

В языках с управляемой памятью не критично, в данном случае все будет ок
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399729
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторНе понял причинно-следственной связи. мы оставляем synchronized дабы исключить параллельное изменение коллекции потоками.
Написал немного не то, что хотел сказать

авторВроде да, должно работать, но по-моему это то же самое, что я написал(спору нет, после Вас).
Это совершенно разные вещи, Вы написали опять с локами, только в отличие от первого варианта с synchronized (который, кстати хотя бы работает), здесь у Вас формально CAS, но только формально, в Вашей реализации это те же локи. Написать над методом non blocking и вставиеь busy-wait - это мощно.

авторя не понял идею. явно где-то не хватает semaphore.take()
В Java SE API))

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

По коду:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
@Override
    public boolean offer(T t) {
        if (locked.compareAndSet(false, true)) {

            if (internalList.size() >= maxSize) { // (A)
                return false; 
            }
            boolean addResult = internalList.add(t);
            locked.set(false); // (B) 
            return addResult;
        }
        return false;
    }


Если срабатывает условие (A) весь стэк навесгда в busy-wait...Ну и немного не понятное у Вас Апи - через offer мы не можем больше max положить, а через put - можем?

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
@Override
    public T take() {
        if (locked.compareAndSet(false, true)) { // (A)
            T t = internalList.get(internalList.size() - 1);
            locked.set(false);
            return t;
        }
        return null;
    }


(A) - допустим у нас есть 1+ элементов в стэке уже и один поток уже получил лок и кладет его туда, тоесть получается вернет null? Хотя там есть элементы...

Нафига AtomicBoolean volatile? Конструктор не safe с точки зрения JLS, хотя на практике спасет хотя бы одно final поле, но я бы так не писал.

Ну и все эти
Код: java
1.
2.
3.
 while (!locked.compareAndSet(false, true)) ;
...
locked.set(false);


ничем не отличаются от lock.lock()/unlock() кроме того, что забываете unlock делать.

авторКак я понимаю мы пытаемся симулировать ситуацию, что между //1 и //2 никаких действий не произошло.
Если произошло - повторяем цикл заново. "!" забыли.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399731
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no56892ничем не отличаются от lock.lock()/unlock() кроме того, что забываете unlock делать
Ну и еще невозможностью "интерраптнуть"
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399738
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no56892no56892ничем не отличаются от lock.lock()/unlock() кроме того, что забываете unlock делать
Ну и еще невозможностью "интерраптнуть"
Нет, такое использование еще даже хуже - процессор жрет.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399806
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никзабыл никпропущено...


Гугли по ключевым словам проблема ABA

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

Да, я гуглил и видел фразу, что в языках с gc ее тяжело воспроизвести. Почему в данном случае все ок будет? Проверка ведь будет успешной.

Смотрите, еще раз, сценарий такой:

1.Первый поток запомнил head
2. Далее другие потоки успели добавить и удалить элемент из стекла
3. Первый поток проверяет, что old == pointer и цикл кончится



Почему мы здесь эту проблему не получим?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399813
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerВдруг будет аргументированная критика.
Ну,
1. Если назвать NonBlocking и потом все на synchronized методах это сильно.
2. Долго выяснять зачем ставить final на поля типа list и maxsize и не сделать этого.
3. Размер списка не уменьшается, мелочь конечно, но тогда почему бы не
Код: java
1.
list = new ArrayList<T>(this.maxSize = maxSize);


4. remove само по себе возвращает объект, повторный поиск лишний.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399816
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerхотя это всё равно не позволит несколько читателей сразу... надо ещё подумать
А нафиг стеку параллельные читатели-писатели?
Овчинка выделки не стоит.

P.S. И мне кажется что массива с указателем текущего положения будет вполне достаточно, ArrayList практически не нужен.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399822
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А главное, кого будум ждать, если тот, кто должен сделать следующий pull пытается сделать push, а стек переполнен.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399825
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати про remove.

Если один и тот же объект у тебя лежит два раза в list.
Что будет по remove(t)?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399833
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей АрсеньевquestionerВдруг будет аргументированная критика.
Ну,
1. Если назвать NonBlocking и потом все на synchronized методах это сильно.

это уже обсудили, Вы не дочитали
Сергей Арсеньев 2. Долго выяснять зачем ставить final на поля типа list и maxsize и не сделать этого.

Похоже и там и там правда нужен. Была мысль, что раз меняем в sync секции, то и не надо, но начальная инициализация может ускользнуть

Сергей Арсеньев 3. Размер списка не уменьшается, мелочь конечно, но тогда почему бы не
Код: java
1.
list = new ArrayList<T>(this.maxSize = maxSize);



такая задача не ставилась

Сергей Арсеньев 4. remove само по себе возвращает объект, повторный поиск лишний.
согласен, но не этот аспект был интересен, поэтому не заморчивался
Сергей АрсеньевЕсли один и тот же объект у тебя лежит два раза в list.
Что будет по remove(t)?

удалится первый, а нужен последний, согласен, но, эти кейсы не столь интересны для меня в этой задаче
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399864
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerудалится первый, а нужен последний, согласен, но, эти кейсы не столь интересны для меня в этой задаче
Для начала надо понять задачу, а потом ее параллелить. Это основной принцип.
Если Вы не уделяете внимания тому, что делаете что вставляем, что удаляем, то браться за параллельное выполнение этих действий - только плодить множество ошибок.

Да и сам выбор задачи не удачен. Профита от неблокирования тут никакого. Тут еще есть смысл в подборе правильной блокировки, поиске зацикливаний и т.п., но не более того.

В смысле неблокирующих операций лучше посмотреть на вариант перевода средств между счетами типа списать у Иванова 10 записать Петрову (желательно, чтоб денег хватало, не было бы взаимоблокировок и чтоб Сидоров не обогатился на этом).
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399911
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никзабыл никпропущено...


Гугли по ключевым словам проблема ABA

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

а тут пишут, что вполне может

http://www.ibm.com/developerworks/library/j-jtp11234/
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399920
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no56892,

no56892Это совершенно разные вещи, Вы написали опять с локами, только в отличие от первого варианта с synchronized (который, кстати хотя бы работает), здесь у Вас формально CAS, но только формально, в Вашей реализации это те же локи. Написать над методом non blocking и вставиеь busy-wait - это мощно.


а вот я правда не очень понимаю чем мой цикл от Вашего отличается. Насчёт дырок в логике, да, всё верно.

скопирую рядом:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
public void push(E element) {
		boolean finish = false;
		do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = new Entry<>(element, currentTop);
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
	}





Код: java
1.
2.
3.
4.
5.
6.
     @Override //blocking
    public void put(T t) throws InterruptedException {
        while (!locked.compareAndSet(false, true)) ;//busy waiting
        internalList.add(t);  //да, здесь нужна проверка на размер предварительно
        locked.set(false);
    }



по-моему у Вас наоборот плохо в цикле, что каждый раз новый объект создаётся. у меня вот один раз я захватил всё добро и только тогда делаю объек, хотя это время лока удлиняет. наверное один раз заранее лучше сделать
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399921
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerзабыл никпропущено...


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

а тут пишут, что вполне может

http://www.ibm.com/developerworks/library/j-jtp11234/

Опять видимо в ваших фантазиях.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399924
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никquestionerпропущено...


а тут пишут, что вполне может

http://www.ibm.com/developerworks/library/j-jtp11234/

Опять видимо в ваших фантазиях.

аргументированно
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399931
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
questionerno56892,

no56892Это совершенно разные вещи, Вы написали опять с локами, только в отличие от первого варианта с synchronized (который, кстати хотя бы работает), здесь у Вас формально CAS, но только формально, в Вашей реализации это те же локи. Написать над методом non blocking и вставиеь busy-wait - это мощно.


а вот я правда не очень понимаю чем мой цикл от Вашего отличается. Насчёт дырок в логике, да, всё верно.

скопирую рядом:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
public void push(E element) {
		boolean finish = false;
		do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = new Entry<>(element, currentTop);
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
	}





Код: java
1.
2.
3.
4.
5.
6.
     @Override //blocking
    public void put(T t) throws InterruptedException {
        while (!locked.compareAndSet(false, true)) ;//busy waiting
        internalList.add(t);  //да, здесь нужна проверка на размер предварительно
        locked.set(false);
    }



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

Мысли спутались пока писал)) у меня ж нет объекта никакого нового, мне его передают.

а у Вас было бы оптимальнее создать объект до цикла, в начале цикла взять струю голову, у созданного объекта настроить ссылку на старый и вызвать CAS
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399937
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerзабыл никпропущено...


Опять видимо в ваших фантазиях.

аргументированно

Мусор на входе = мусор на выходе
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399938
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никquestionerпропущено...


аргументированно

Мусор на входе = мусор на выходе

я ссылку привел. вот цитата из нее:

http://www.ibm.com/developerworks/library/j-jtp11234/ The ABA problem
Because CAS basically asks "is the value of V still A" before changing V, it is possible for a CAS-based algorithm to be confused by the value changing from A to B and back to A between the time V was first read and the time the CAS on V is performed. In such a case, the CAS operation would succeed, but in some situations the result might not be what is desired. (Note that the counter and mutex examples from Listing 1 and Listing 2 are immune to this problem, but not all algorithms are.) This problem is called the ABA problem, and is generally dealt with by associating a tag, or version number, with each value to be CASed, and atomically updating both the value and the tag. The AtomicStampedReference class provides support for this approach.


Статья про атомики
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399945
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no56892Вот это lock-free стэк:
Это ,так называемый, lock-free стэк.
Ибо
1. compareAndSet - это и есть блокировка, просто она wait free. Вслед за этим все заворачивается в цикл, который как раз и реализует это ожидание. Поэтому алгоритм не "без блокировок" и не "без ожиданий".

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

3. Гонять в цикле генератор новый Entry, при том, что достаточно менять одну ссылку это перебор.

3а.
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = null;
			if(currentTop != null) {
				ret = currentTop.element;	
				newTop = currentTop.prev;
			}
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);


При пустом стеке может забрать новый элемент. Что, правда, может и не плохо.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399946
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerзабыл никпропущено...


Мусор на входе = мусор на выходе

я ссылку привел. вот цитата из нее:


Я видел, не поленился даже поискать, и только после этого и ответил. Как это расходится с моими словами?
Где там хоть слово про стэк и managed память? Все зависит от алгоритма. В unmanaged языках существует дополнительная проблема, когда поток держит ссылку, которая уже удалена другим потоком и потом может внезапно обновиться
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399965
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerСтатья про атомики
В данном случае, никогда не будет удачной попытки вставить один и тот же элемент (Entry) в силу этого и не может повторно оказаться та же величина для сравнения.
Просто реализовывать свою блокировку на атомиках через true false, а безсмысленно, б уж лучше id потока использовать на предмет кто последний захватил, типа
Код: java
1.
while(!compareAndSet(null,я)){не удалось, ждемс или делаем, что-нибудь полезное}
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39399967
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

Точнее может, но это не важно, в этом случае нам не важно, что в промежутке вершина стека менялась, главное, что на этот момент она там же и ничего ниже ее не вынималось.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400012
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей АрсеньевВ данном случае, никогда не будет удачной попытки вставить один и тот же элемент

почему?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400015
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей Арсеньев,

тогда операция ведь формально не атомарно.

между взятием старого значения и проверкой могло произойти вставка ещё 100 элементов сверху и 101-ым вставили опять старый элемент
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400020
Фотография Hett
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400027
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerСергей Арсеньев,

тогда операция ведь формально не атомарно.

между взятием старого значения и проверкой могло произойти вставка ещё 100 элементов сверху и 101-ым вставили опять старый элемент
И что это меняет? Вам вот правильно говорят, сначала определитесь как алгоритм в вашем понимании должен ПРАВИЛЬНО работать. Есть fair-locking, когда важно в каком порядке будут вставляться элементы(или изменяться shared объекты), а когда необходима просто консистентность. В вашем случае нужна просто консистентность, так что неважно что еще 100 потоков там что-то надобавлялт, структура ведь остается корректной
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400030
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл ника когда необходима просто консистентность.

Читать как "а есть non-fair когда необходима просто консистентность."
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400035
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerмежду взятием старого значения и проверкой могло произойти вставка ещё 100 элементов сверху и 101-ым вставили опять старый элемент
Поэтому вставляют и сравнивают не сам элемент, а Entry. Которое по сути является ссылкой на этот элемент и на предыдущее Entry. Entry для каждой вставки новое.
Да алгоритм проигнорирует ситуацию, когда прошло 100 (n) вставок и 100 (n) забираний элементов между получением старой вершины и попыткой вставки новой. Но в данном случае это не важно.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400042
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей Арсеньевquestionerмежду взятием старого значения и проверкой могло произойти вставка ещё 100 элементов сверху и 101-ым вставили опять старый элемент
Поэтому вставляют и сравнивают не сам элемент, а Entry. Которое по сути является ссылкой на этот элемент и на предыдущее Entry. Entry для каждой вставки новое.
Да алгоритм проигнорирует ситуацию, когда прошло 100 (n) вставок и 100 (n) забираний элементов между получением старой вершины и попыткой вставки новой. Но в данном случае это не важно.

это меткое замечание
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400054
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл ник структура ведь остается корректной
Для понятия "стек" важен порядок вставки и забирания элементов (LIFO). Если он не важен, то это уже не стек.

Более того, в силу того, что в отличии от очереди, тут не получится даже развести читателя и писателя (они конкурируют за право изменить один и тот же указатель). А действий, которые надо совершить (проверка заполненности, изменение указателя вершины, возможно обнуление старой ссылки, возврат значения), раз-два и обчелся. Смысла нет обойтись без блокировки - можно не не такой уж и выигрыш по скорости, плюс расходы на генерацию (и последующую работу GC) новых Entry (против массива и индекса вершины). Не та задача, где стоит ломать копья.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400063
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Hett,

Так человек сам до этого дойти хочет. Но там все на synchronized . А люди жаждут приключений.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400080
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньевзабыл ник структура ведь остается корректной
Для понятия "стек" важен порядок вставки и забирания элементов (LIFO). Если он не важен, то это уже не стек.

Более того, в силу того, что в отличии от очереди, тут не получится даже развести читателя и писателя (они конкурируют за право изменить один и тот же указатель). А действий, которые надо совершить (проверка заполненности, изменение указателя вершины, возможно обнуление старой ссылки, возврат значения), раз-два и обчелся. Смысла нет обойтись без блокировки - можно не не такой уж и выигрыш по скорости, плюс расходы на генерацию (и последующую работу GC) новых Entry (против массива и индекса вершины). Не та задача, где стоит ломать копья.

Эмм, а кто спорит? Если вы про то что я криво вас процитировал, то это глюк сайта, я отвечал ТС. Видимо ему бороться с ветряными мельницами просто необходимо
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400096
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никquestionerСергей Арсеньев,

тогда операция ведь формально не атомарно.

между взятием старого значения и проверкой могло произойти вставка ещё 100 элементов сверху и 101-ым вставили опять старый элемент
И что это меняет? Вам вот правильно говорят, сначала определитесь как алгоритм в вашем понимании должен ПРАВИЛЬНО работать. Есть fair-locking, когда важно в каком порядке будут вставляться элементы(или изменяться shared объекты), а когда необходима просто консистентность. В вашем случае нужна просто консистентность, так что неважно что еще 100 потоков там что-то надобавлялт, структура ведь остается корректной

У меня диссонанс из-за того, что атомики не атомарны в моём понимании(наверное оно ошибочно)

когда меня спрашивают на собесах что это такое и зачем они нужны я даю ответ, что они нужны для того, чтобы другой поток не вклинился между двумя операциями (increment and get допустим)?

и я так понимал код, что между взятием старого значения и присвоением нового ничего не должно произойти, иначе новый цикл. а тут не совсем так получается.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400100
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никЭмм, а кто спорит? Если вы про то что я криво вас процитировал, то это глюк сайта, я отвечал ТС. Видимо ему бороться с ветряными мельницами просто необходимо
пфф, я изучаю инструмент, не более того
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400107
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerУ меня диссонанс из-за того, что атомики не атомарны в моём понимании(наверное оно ошибочно)

У Атомика есть куча операций, которые атомарны. Не более не менее.
Между ними никакой атомарности никто не обещал.
Для этого:
YouTube Video
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400129
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей АрсеньевquestionerУ меня диссонанс из-за того, что атомики не атомарны в моём понимании(наверное оно ошибочно)

У Атомика есть куча операций, которые атомарны. Не более не менее.
Между ними никакой атомарности никто не обещал.
Для этого:
YouTube Video
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400146
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerУ нас тут явно недопонимание
По шагам.
У атомика есть ряд атомарных операций.
1. pointer.get();
Атомарно
2. pointer.compareAndSet(currentTop, newTop);
Атомарно

Но никто не обещает Атомарность этих действий вместе. Поэтому между ними может вклинится кто-то другой.
Сам по себе atomic не ведет учет своего состояния, поэтому нет операции ifNotChangedSet(). Делается через проверку старого значения. Но совпадение старого значения, не означает что состояние не менялось. В случае вставки в стек это все равно - при farness это не важно, главное, что вставляем в вершину. А это Atomic гарантирует, если это уже не тот экземпляр, то присвоения не будет (для этого у ней внутре миниблокировка, со всеми h-b бонусами, в отличии от weakCompareAndSet).
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400260
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автор1. compareAndSet - это и есть блокировка, просто она wait free. Вслед за этим все заворачивается в цикл, который как раз и реализует это ожидание. Поэтому алгоритм не "без блокировок" и не "без ожиданий".

Строго говоря, это lock-free называется, см. http://www.1024cores.net/home/in-russian/lock--wait--obstruction--atomic-free-algorithms

автор2. Это даже не стек. Ибо в силу отсутствия сериализации вполне допускается ситуация, когда поток будет пытаться вставить элемент, но у него это достаточно долго не будет получаться, при том, что другие потоки будут вставлять и вынимать объекты из "стека".
Это starvation, есть такое, но из этого не следует, что это перестает быть стеком, следуя такой логике Collections.synchronized(deque) это тоже не стек, да и ConcurrentLinkedDeque тоже не стек.

авторГонять в цикле генератор новый Entry, при том, что достаточно менять одну ссылку это перебор.
+

авторПри пустом стеке может забрать новый элемент. Что, правда, может и не плохо.
+, надо добавить else return null;

Да, кстати, а как наличие GC отменяет ABA? Вполне теоретически возможна ситуация, когда Entry собирается GC и new Entry возвращает объект по тому же адресу.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400325
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no56892Это starvation, есть такое, но из этого не следует, что это перестает быть стеком, следуя такой логике Collections.synchronized(deque) это тоже не стек, да и ConcurrentLinkedDeque тоже не стек.
Ты не поверишь, но и java.util.Stack тоже не гарантирует порядка в этом вопросе. :)
А так да.


no56892Да, кстати, а как наличие GC отменяет ABA? Вполне теоретически возможна ситуация, когда Entry собирается GC и new Entry возвращает объект по тому же адресу.
Ну если Entry не пересоздавать в цикле ожидания, то проблемы быть не должно.:)
Ибо GC он не достанется, так как удерживается переменной в стеке потока, а то, что добавлено в "стек" удерживается "стеком".
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400327
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Только Entry надо создать до pointer.get();
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400330
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

это я перемудрил
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400334
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторНу если Entry не пересоздавать в цикле ожидания, то проблемы быть не должно.:)
Ибо GC он не достанется, так как удерживается переменной в стеке потока, а то, что добавлено в "стек" удерживается "стеком".
Да, точно, я тупанул

questioner, ну, что, придумал как написать size()?))
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400339
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
Entry<E> currentTop = pointer.get();


До этого момента Entry держится pointer, потом currentTop.
Поэтому, эта ссылка не может собраться и выдаться еще кому-нибудь.
Поэтому, повторно в стек попасть не может вплоть до конца цикла.
А compareAndSet(currentTop, newTop) раньше.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400459
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no56892questioner, ну, что, придумал как написать size()?))

так наверное:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
 public int size() {
        do {
            Entry<E> oldPointer = pointer.get();
            Entry<E> entry = oldPointer;
            int size = 0;
            while (entry != null) {
                size++;
                entry = entry.prev;
            }
            if (pointer.compareAndSet(oldPointer, oldPointer)) {
                return size;
            }
        } while (true);
    }
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400466
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
хотя cas операция тут как-то ни к селу ни к городу. обычный if можно написать. Меня чего-то терзают смутные сомнения в нужности cas в данном случае
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400483
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerМеня чего-то терзают смутные сомнения в нужности cas в данном случае
Забей. size() вполне может устареть к моменту возврата результата.
Тут важно гарантировать, что цепочка не порвется или еще хуже -сама замкнется, пока по ней бегут.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400503
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей АрсеньевquestionerМеня чего-то терзают смутные сомнения в нужности cas в данном случае
Забей. size() вполне может устареть к моменту возврата результата.
Тут важно гарантировать, что цепочка не порвется или еще хуже -сама замкнется, пока по ней бегут.

Хм, тогда мой вариант совсем не будет работать.

Тогда либо как-то(не знаю как) лочить коллекцию целиком на время исполнения метода, либо держать atomicLong который будет трекать pop/push. Но опять же данные могут быть слегка неконсистентные.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400548
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Реализация метода size() в SynchronizedCollection<E> :
Код: java
1.
2.
3.
public int size() {
    synchronized (mutex) {return c.size();}
}


P.S.
SynchronizedCollection<E> - synchronized-обертка на обычной коллекцией.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400604
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Usman,

В Synchronizedxxx все методы синхронизированы, поэтому и работать будет, а тут ведь просят для неблокирубщего алгоритма, тут скорее надо смотреть в сторону CHM
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400605
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Usman,

Но тогда можно пользоваться только синхро коллекцией. А в чем смысл?


questioner,
Но поскольку Entry не меняются после добавления в стек, даже при извлечении объекта из стека, то цепочка не разорвется. Даже если извлечения обгонят size(). И потому, что size() будет их удерживать их не соберет GC.
Единственное но - при многопоточной работе, size() всегда имеет справочный характер и может устареть в любой момент, в т.ч. до возврата результата.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400610
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хочешь задачку?

Сделать аналогичный "стек", позволяющий вынуть как одно, так и два значения подряд.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400618
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей АрсеньевUsman,

Но тогда можно пользоваться только синхро коллекцией. А в чем смысл?


questioner,
Но поскольку Entry не меняются после добавления в стек, даже при извлечении объекта из стека, то цепочка не разорвется. Даже если извлечения обгонят size(). И потому, что size() будет их удерживать их не соберет GC.
Единственное но - при многопоточной работе, size() всегда имеет справочный характер и может устареть в любой момент, в т.ч. до возврата результата.

Кстати да, при таком подходе, объекты не будут удаляться из памяти. Memory leak. OutOfMemory может быть
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400635
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Почему же? Всю цепочку держит голова. Как она спускается по цепочке - объект становится собираемым.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400697
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей Арсеньевquestioner,

Почему же? Всю цепочку держит голова. Как она спускается по цепочке - объект становится собираемым.

Хм, действительно
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400702
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Хм, действительно

Ну что, пора уже к Art of Multiprocessor programming приступать?:) Эта книга сложная но must-read. Ну и упражнений там куча
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400855
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сергей АрсеньевХочешь задачку?

Сделать аналогичный "стек", позволяющий вынуть как одно, так и два значения подряд.

Как он должен себя если просят вынуть два значения, а есть только одно?
в каком формате их выплёвывать? в массиве?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400868
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerВ Synchronizedxxx все методы синхронизированы, поэтому и работать будет, а тут ведь просят для неблокирубщего алгоритмаСергей АрсеньевНо тогда можно пользоваться только синхро коллекцией. А в чем смысл?Ок. Можно завести одну переменную, которая и будет хранить общее кол-во элементов. Увеличивать при добавлении, уменьшать при удалении и т.д.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400940
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
UsmanОк. Можно завести одну переменную, которая и будет хранить общее кол-во элементов. Увеличивать при добавлении, уменьшать при удалении и т.д.

http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1249068&msg=20190919 ..... либо держать atomicLong который будет трекать pop/push. Но опять же данные могут быть слегка неконсистентные.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400945
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerНо опять же данные могут быть слегка неконсистентные.это зависит от реализации pop/push
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400987
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
UsmanquestionerНо опять же данные могут быть слегка неконсистентные.это зависит от реализации pop/push
Но в любом случае, если не запретить эти операции до запроса, результат может быть не актуальным.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39400995
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевUsmanпропущено...
это зависит от реализации pop/push
Но в любом случае, если не запретить эти операции до запроса, результат может быть не актуальным.В отличии от чтения, запись всегда должна быть блокирующей.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401004
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Usman,

Мы про подсчет количества? Еще раз повторю - если не запретить изменения результат может быть не актуален чуть ранее чем известен.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401013
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

Поясните разницу между блокировкой и запретом?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401066
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Usman,

Синонимы. Я про то, что блокировку надо ставить тогда до начала size() и не отменять, пока результат не будет применен. А этого тут хотели бы избежать. :)
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401080
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньевблокировку надо ставить тогда до начала size() и не отменять, пока результат не будет применен. А этого тут хотели бы избежать. :)Только в том случае, если подсчет елементов будет непосредственно внутри метода size().

Сергей Арсеньев, http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1249068&msg=20190919 atomicLong который будет трекать pop/pushА как на счет такого?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401122
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
UsmanСергей Арсеньевблокировку надо ставить тогда до начала size() и не отменять, пока результат не будет применен. А этого тут хотели бы избежать. :)Только в том случае, если подсчет елементов будет непосредственно внутри метода size().

Сергей Арсеньев, http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1249068&msg=20190919 atomicLong который будет трекать pop/pushА как на счет такого?
ну так мы сможем этот atomicLong инкрементить только уже после того, как compareAndSet сработал. и соответственно действие будет не атомарно
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401137
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerну так мы сможем этот atomicLong инкрементить только уже после того, как compareAndSet сработал. и соответственно действие будет не атомарноИсхожу из этого:UsmanВ отличии от чтения, запись всегда должна быть блокирующей.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401171
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
UsmanТолько в том случае, если подсчет елементов будет непосредственно внутри метода size().
Это не важно. В любой момент в том числе и в момент возврата из метода size() ситуация может измениться и число будет не актуально. И даже раньше. К тому моменту, как любой счетчик вернет значение, оно уже может устареть. Поэтому либо полная остановка изменяющих нитей, либо не актуальность.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401192
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев Поэтому либо полная остановка изменяющих нитей, либо не актуальность.

Ну в теории ведь есть multi CAS, допустим хранить счетчик размера стэка в отдельном поле и CASиться по нему и верху стэка. Не практично само собой, так, чтоб дискуссию поддержать:)
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401201
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевНо тогда можно пользоваться только синхро коллекцией. А в чем смысл?Смысл в актуальности (:
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401204
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никСергей Арсеньев Поэтому либо полная остановка изменяющих нитей, либо не актуальность.

Ну в теории ведь есть multi CAS, допустим хранить счетчик размера стэка в отдельном поле и CASиться по нему и верху стэка. Не практично само собой, так, чтоб дискуссию поддержать:)

а как это сделать?

одновременно CASиться по размеру и по неизменной голове стека?

код, плиз
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401215
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
/**
 * Returns the number of elements in this queue.  If this queue
 * contains more than {@code Integer.MAX_VALUE} elements, returns
 * {@code Integer.MAX_VALUE}.
 *
 * <p>Beware that, unlike in most collections, this method is
 * <em>NOT</em> a constant-time operation. Because of the
 * asynchronous nature of these queues, determining the current
 * number of elements requires an O(n) traversal.
 * Additionally, if elements are added or removed during execution
 * of this method, the returned result may be inaccurate.  Thus,
 * this method is typically not very useful in concurrent
 * applications.
 *
 * @return the number of elements in this queue
 */
public int size() {
    int count = 0;
    for (Node<E> p = first(); p != null; p = succ(p))
        if (p.item != null)
            // Collection.size() spec says to max out
            if (++count == Integer.MAX_VALUE)
                break;
    return count;
}

тынц
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401216
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Usman,

а это на что ответ?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401217
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

По поводу реализации метода size()
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401246
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тут на самом деле 3 варианта (по степени возростания консистентности (отражения реального положения дел в стеке)):
1. Тупо получить ссылку на топ и пройтись до null, просуммировав количество элементов
Это O(n)
2. Добавить AtomicLong и перед put/pop инкрементить/декрементить
Это O(1)
3. Добавить поле long index в Entry, и присваивать его в момент создания Entry, тогда получить размер будет - topPointer.get().index;
Это тоже O(1). Здесь тоже возможна ситуация когда между topPointer.get() и получением поля index будет вставлен(ы) элемент(ы), но операций требуется значительно меньше, чем с AtomicLong. Мое имхо, мне больше нравится этот способ : ).

В ConcurrentLinkedList по O(1) размер уже не вернешь видимо...
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401251
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no568923. Добавить поле long index в Entry, и присваивать его в момент создания Entry, тогда получить размер будет - topPointer.get().index;
Это тоже O(1). Здесь тоже возможна ситуация когда между topPointer.get() и получением поля index будет вставлен(ы) элемент(ы), но операций требуется значительно меньше, чем с AtomicLong. Мое имхо, мне больше нравится этот способ : ).

В ConcurrentLinkedList по O(1) размер уже не вернешь видимо...

Ну взяли вы индекс - например 9, начали создавать Entry, заснули, пришло еще 3 потока, индекс уже 12, это не вариант
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401252
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никno568923. Добавить поле long index в Entry, и присваивать его в момент создания Entry, тогда получить размер будет - topPointer.get().index;
Это тоже O(1). Здесь тоже возможна ситуация когда между topPointer.get() и получением поля index будет вставлен(ы) элемент(ы), но операций требуется значительно меньше, чем с AtomicLong. Мое имхо, мне больше нравится этот способ : ).

В ConcurrentLinkedList по O(1) размер уже не вернешь видимо...

Ну взяли вы индекс - например 9, начали создавать Entry, заснули, пришло еще 3 потока, индекс уже 12, это не вариант
Индекс присваивается до CAS, если пришло еще 3 потока, то когда проснемся CAS не пройдет, цикл повторится и уже будем новый индекс вставлять...
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401255
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerзабыл никпропущено...


Ну в теории ведь есть multi CAS, допустим хранить счетчик размера стэка в отдельном поле и CASиться по нему и верху стэка. Не практично само собой, так, чтоб дискуссию поддержать:)

а как это сделать?

одновременно CASиться по размеру и по неизменной голове стека?

код, плиз

Ага, может еще и ключи от квартиры? Я же говорю, что в ТЕОРИИ.
Просто лень напрягать мозги в выдуманной ситуации, то что метод size() в конкурентной коллекции может выдавать не всегда конкретные ответы, это разумный компромисс.
Но, если бы вдруг мне понадобилось что-нибудь этакое, на multi-CAS, я бы начал смотреть вот отсюда - AtomicMarkableReference
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401256
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no56892Индекс присваивается до CAS, если пришло еще 3 потока, то когда проснемся CAS не пройдет, цикл повторится и уже будем новый индекс вставлять...

Я немного запутался о какой версии кода вы уже тут говорите:) Как у вас CAS от индекса зависит? Я к тому что compareAndSwapить будете?
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401262
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл ник,

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
class ConcurrentStack<E> {
	
	private final AtomicReference<Entry<E>> pointer = new AtomicReference<>();
	
	public void push(E element) {
		boolean finish = false;
		final Entry<E> newTop = new Entry<>(element);
		do {
			Entry<E> currentTop = pointer.get();
			newTop.setPrev(currentTop);
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
	}
	
	public E pop() {
		E ret = null;
		boolean finish = false;
		do {
			Entry<E> currentTop = pointer.get();
			Entry<E> newTop = null;
			if(currentTop != null) {
				ret = currentTop.element;	
				newTop = currentTop.prev;
			} else {
				return null;
			}
			finish = pointer.compareAndSet(currentTop, newTop);
		} while(!finish);
		return ret;
	}
	
	public long size() {
		Entry<E> current = pointer.get();
		return current != null?current.index:0;
	}
	
	private static class Entry<E> {
		private E element; 
		private Entry<E> prev; 
		private long index = 1;

		Entry(E element) {
			this.element = element;
		}
		
		void setPrev(Entry<E> prev) {
			this.prev = prev;
			if(prev != null) {
				index = prev.index + 1;
			}
		}
	}
}
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401266
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
UsmanСергей АрсеньевНо тогда можно пользоваться только синхро коллекцией. А в чем смысл?Смысл в актуальности (:
А как синхроколлекция даст актуальность?
Ведь в момент return число может стать уже не соответствующим действительности.
В силу этого ни о какой актуальности речи не будет.
Блокировка должна быть до конца применения значения size(), типа:
Код: java
1.
if(stack.size()>0) stack.pull().toString();

может вызвать NPE.
Посему какая разница неправильный размер он был получен внутри или снаружи.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401267
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никЯ немного запутался о какой версии кода вы уже тут говорите:) Как у вас CAS от индекса зависит? Я к тому что compareAndSwapить будете?
Он имеет ввиду, что присвоение одному AtomicReference (ссылки на голову) и увеличение другого AtomicInteger (счетчика) одновременно не сделаешь. А значит size на основе счетчика может вернуть не правду. Правда оно и не важно. :)
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401269
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

Конечно если не делать вариант, что Entry сразу хранит счетчик. :)
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401276
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев Блокировка должна быть до конца применения значения size()
В таком варианте да, а вот например:
Код: java
1.
2.
3.
if(concurrentStack.size() > 100) {
  //increase number of popping threads
}


вполне себе нормально
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401284
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевА как синхроколлекция даст актуальность?на момент возвращения будет актуальное значениеСергей АрсеньевВедь в момент return число может стать уже не соответствующим действительности.в момент выхода из синхро-блока (если потоки все еще "крутятся")
Сергей АрсеньевВ силу этого ни о какой актуальности речи не будет.см. 20194593 :

Код: plaintext
Thus, this method is typically not very useful in concurrent applications.

Сергей АрсеньевБлокировка должна быть до конца применения значения size()А вот тут я соглашусь.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401328
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no568922. Добавить AtomicLong и перед put/pop инкрементить/декрементить
Это O(1)


а можно ведь только однажды это сделать перед возвращением значения пользователю
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401393
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никНу взяли вы индекс - например 9, начали создавать Entry, заснули, пришло еще 3 потока, индекс уже 12, это не вариант
Entry засунется только тогда, когда между ним и головой никто не успел всунуться.
Если успели все одно Entry переделывать перед новой попыткой вставки.
Так что метод относительно действенный. Если только не бесполезный.
...
Рейтинг: 0 / 0
codereview самописный потокобезопасный stack
    #39401396
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerno568922. Добавить AtomicLong и перед put/pop инкрементить/декрементить
Это O(1)

а можно ведь только однажды это сделать перед возвращением значения пользователю
Только вот то, что запрос значения может оказаться раньше инкремента/декремента может привести к тому, что значение будет чуть менее чем полностью отличаться от актуального.
Что правда не важно. :)
...
Рейтинг: 0 / 0
120 сообщений из 120, показаны все 5 страниц
Форумы / Java [игнор отключен] [закрыт для гостей] / codereview самописный потокобезопасный stack
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]