不使用`synchronized`关键字的线程安全代码?

没有使用synchronized关键字,有什么方法可以使代码线程安全?

实际上,有很多方法:

  1. 如果您没有可变状态,则根本不需要同步。
  2. 如果可变状态仅限于单个线程,则无需同步。 这可以通过使用局部变量或java.lang.ThreadLocal来完成。
  3. 您还可以使用内置同步器。 java.util.concurrent.locks.ReentrantLock与使用synchronized块和方法时访问的锁具有相同的function,而且function更强大。

只有方法的局部变量/引用。 或者确保任何实例变量都是不可变的。

您可以通过使所有数据不可变来使您的代码成为线程安全的,如果没有可变性,一切都是线程安全的。

其次,您可能需要查看java并发API,它提供了提供读/写锁定的function,以便在有大量读取器和少量编写器时性能更佳。 Pure synchronized关键字也会阻止两个读者。

为了保持可预测性,您必须确保按顺序访问可变数据,或者处理由并行访问引起的问题。

最严重的保护使用synchronized关键字。 除此之外,至少有两层可能性,每一层都有其优点。

锁/信号灯

这些可能非常有效。 例如,如果您有一个由许multithreading读取但只更新一个的结构,您可能会发现ReadWriteLock很有用。

如果您选择锁定以匹配算法,则锁定效率会更高。

primefaces能

例如,使用AtomicReference通常可以提供完全无锁的function。 这通常可以带来巨大的好处。

primefaces论背后的原因是允许它们失败,但告诉你它们以你能够处理它的方式失败了。

例如,如果要更改值,可以读取它,然后写入新值,只要它仍然是旧值。 这称为“比较和设置”或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(); } 

但请注意,可预测性并不总是要求。

那么你可以通过很多方法实现这一目标,但每种方法都包含很多种口味。 Java 8还附带了新的并发function。 您可以通过以下方式确保线程安全:
Semaphores
Locks- Reentrantlock,ReadWriteLock,StampedLock (Java 8)

  ////////////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(); 

你为什么需要这样做?

仅使用本地变量/引用不能解决大多数复杂的业务需求。 此外,如果实例变量是不可变的,则其他线程仍可以更改其引用。

一种选择是使用类似SingleThreadModel的东西,但强烈建议不要使用它。

你也可以看看Kal上面建议的并发api