Вопрос по java, multithreading – Потокобезопасный код без использования ключевого слова synchronized?

13

Каковы возможные способы сделать код потокобезопасным без использованияsynchronized ключевое слово?

@NimChimpsky & quot; Слишком широко & quot; Я предполагаю. OrangeDog
почему близко? Это хороший лаконичный вопрос NimChimpsky
@NimChimpsky Я тоже не знаю, вопрос кажется мне вполне уместным. Это определенно ответственно, и ответы не являются чем-то субъективным. Malcolm

Ваш Ответ

7   ответов
-2

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

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

Вы также можете посмотреть на параллельный API, как предложено вышеKal

со строкой s ваша ссылка не является неизменной, она может ссылаться на другую строку, просто выполнив s = & quot; yourarewrong & quot ;. Вы говорите, что неизменяемые переменные экземпляра не являются потокобезопасными, а затем приводите пример изменяемой переменной экземпляра.
& quot; если переменные экземпляра являются неизменными, их ссылки все еще могут быть изменены & quot; нет, они не могут
s - это ссылка, она изменилась, она не является неизменной, вам понадобится & quot; последняя строка s & quot;
ты можешь это объяснить. Как я вижу, если у меня есть переменная экземпляра String s = "xyz", мой поток1 может изменить ссылку на нее на s = "abc"; и thread2 теперь получит s = & quot; abc & quot;
0

есть много способов достичь этого, но каждый содержит много вкусов. Java 8 также поставляется с новыми функциями параллелизма. Вот несколько способов убедиться в безопасности потоков:
Semaphores
Замки-Reentrantlock,ReadWriteLock,StampedLock(Java 8)

5

что любые переменные экземпляра неизменны.

Не будут ли неизменные переменные экземпляра приемлемыми?
хороший - короткий & amp; к точке.
@duffymo отредактировано
10

No need for synchronization at all if you don't have mutable state. No need for synchronization if the mutable state is confined to a single thread. This can be done by using local variables or java.lang.ThreadLocal. You can also use built-in synchronizers. java.util.concurrent.locks.ReentrantLock has the same functionality as the lock you access when using synchronized blocks and methods, and it is even more powerful.
Не берите в голову - я могу, используя java.util.concurrent.Semaphore.
@PeterLawrey - так, потокобезопасный код без «синхронизированного» Ключевое слово, безусловно, возможно и, на самом деле, практично. Теперь осталось только заставить разработчиков прекратить использовать Thread.join (), и мы закончили :)
@MartinJames Лучше сказать, что потокобезопасный код возможен безlocking, Иногда вы можете избежать использования блокировок полностью (внутренние блокировки или нет, это неважно), и тогда все становится намного проще. Однако, если вы доберетесь до блокировки, лучше использоватьsynchronized чем внешние блокировки, если вам не нужны расширенные функции. Обозначение внутренних блокировок является кратким, и код не должен содержать блоки try-finally (следовательно, намного более безопасные).
Я предпочитаю (2), но я не уверен, что это так. возможно реализовать передачу сообщений без использования «синхронизированного»; ключевое слово. Могу ли я создать очередь «производитель-потребитель» без «синхронизации»?
@MartinJames Любой из классов Concurrent, таких как Queues и Exchangers, можно использовать без синхронизации. (Вместо этого они используют блокировку) Disrupter поддерживает обмен сообщениями без блокировок или синхронизации. (У меня есть библиотека, которая делает это тоже)
1

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

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

Locks/Semaphores

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

Блокировки могут быть намного эффективнее, если вы выберете блокировку, соответствующую алгоритму.

Atomics

ИспользованиеAtomicReference например, часто может предоставить полностью блокированную свободную функциональность. Это обычно может дать огромные преимущества.

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

Например, если вы хотите изменить значение, вы можете прочитать его, а затем записать его новое значение, если оно все еще является старым значением. Это называется "сравнить и установить" или жеcas и, как правило, может быть реализовано аппаратно и, следовательно, чрезвычайно эффективно. Все, что вам тогда нужно, это что-то вроде:

long old = atomic.get();
while ( !atomic.cas(old, old+1) ) {
  // The value changed between my get and the cas. Get it again.
  old = atomic.get();
}

Обратите внимание, однако, что предсказуемость не всегда является требованием.

4

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

Во-вторых, вы можете захотеть взглянуть на параллельный API java, в котором предусмотрены блокировки для чтения / записи, которые работают лучше, если есть много читателей и несколько писателей. Чистое синхронизированное ключевое слово также заблокирует двух читателей.

0

   ////////////FIRST METHOD USING SINGLE boolean//////////////


    public class ThreadTest implements Runnable { 
        ThreadTest() {
            Log.i("Ayaz", "Constructor..");
        }

        private boolean lockBoolean = false;

        public void run() {
            Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName());
            while (lockBoolean) {
             // infinite loop for other thread if one is accessing
            }
            lockBoolean = true;
            synchronizedMethod();
        }

        /**
         * This method is synchronized without using synchronized keyword
         */
        public void synchronizedMethod() {
            Log.e("Ayaz", "processing...." + Thread.currentThread().getName());
            try {
                Thread.currentThread().sleep(3000);
            } catch (Exception e) {
                System.out.println("Exp");
            }
            Log.e("Ayaz", "complete.." + Thread.currentThread().getName());
            lockBoolean = false;
        }

    } //end of ThreadTest class

     //For testing use below line in main method or in Activity
     ThreadTest threadTest = new ThreadTest();
            Thread threadA = new Thread(threadTest, "A thead");
            Thread threadB = new Thread(threadTest, "B thead");
            threadA.start();
            threadB.start();

///////////SECOND METHOD USING TWO boolean/////////////////



 public class ThreadTest implements Runnable {
    ThreadTest() {
        Log.i("Ayaz", "Constructor..");
    }

    private boolean isAnyThreadInUse = false;
    private boolean lockBoolean = false;

    public void run() {
        Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName());
        while (!lockBoolean)
            if (!isAnyThreadInUse) {
                isAnyThreadInUse = true;
                synchronizedMethod();
                lockBoolean = true;
            }
    }

    /**
     * This method is synchronized without using synchronized keyword
     */
    public void synchronizedMethod() {
        Log.e("Ayaz", "processing...." + Thread.currentThread().getName());
        try {
            Thread.currentThread().sleep(3000);
        } catch (Exception e) {
            System.out.println("Exp");
        }
        Log.e("Ayaz", "complete.." + Thread.currentThread().getName());
        isAnyThreadInUse = false;
    }

} // end of ThreadTest class

     //For testing use below line in main method or in Activity
     ThreadTest threadTest = new ThreadTest();
     Thread t1 = new Thread(threadTest, "a thead");
     Thread t2 = new Thread(threadTest, "b thead");
     t1.start();
     t2.start();

Похожие вопросы