14

What are the possible ways to make code thread-safe without using the synchronized keyword?

4

7 回答 7

11

其实方法很多:

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

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

于 2012-04-26T09:46:06.877 回答
4

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

其次,您可能想看看 java 并发 API,它提供了读/写锁,在有很多读者和少数写者的情况下表现更好。纯同步关键字也会阻止两个阅读器。

于 2012-04-26T09:48:09.147 回答
4
   ////////////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();
于 2018-08-03T11:40:45.877 回答
2

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

最粗暴的保护使用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();
}

但是请注意,可预测性并不总是必需的。

于 2012-04-26T10:34:15.773 回答
0

那么有很多方法可以实现这一点,但每种方法都包含多种口味。Java 8 还附带了新的并发特性。可以确保线程安全的一些方法是:
Semaphores
Locks- Reentrantlock,ReadWriteLock,StampedLock(Java 8)

于 2018-05-23T09:18:16.723 回答
-2

为什么你需要这样做?

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

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

您还可以查看Kal上面建议的并发 api

于 2012-04-26T10:01:44.137 回答