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

时间:2012-04-26 09:44:44

标签: java multithreading

在不使用synchronized关键字的情况下,有哪些方法可以使代码保持线程安全?

7 个答案:

答案 0 :(得分:10)

实际上,有很多方法:

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

答案 1 :(得分:5)

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

答案 2 :(得分:4)

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

其次,您可能需要查看java并发API,它提供了提供读/写锁的功能,以便在有大量读者和少量编写器的情况下执行更好。 Pure synchronized关键字也会阻止两个读者。

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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

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

<强>锁/信号量

这些非常有效。例如,如果您的结构被许多线程读取但只更新了一个,那么您可能会发现ReadWriteLock有用。

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

<强>原子公司

例如,使用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();
}

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

答案 5 :(得分:0)

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

答案 6 :(得分:-2)

为什么你需要这样做?

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

一个选项是使用类似SingleThreadModel的内容,但强烈建议不要使用它。

你也可以通过 Kal

看上面建议的并发api