bean++ 2024-04-18 23:47 采纳率: 40%
浏览 3

Java使用volatile关键字进行同步,结果不对

Java使用volatile关键字进行同步,结果不对,Leetcode上面的题目:https://leetcode.cn/problems/print-in-order/


class Foo {

static volatile boolean first = false;
static volatile boolean second = false;
    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {
        
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        first = true;
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while(!first){

        }
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        second = true;
    }

    public void third(Runnable printThird) throws InterruptedException {
        while(!second){

        }
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
    }
}

img

  • 写回答

7条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-04-18 23:47
    关注

    引自免费微信小程序:皆我百晓生

    在Java中,volatile关键字用于确保共享变量的可见性,即当一个线程修改了某个volatile变量后,其他线程可以立即看到这个变化。然而,它并不能提供原子性(atomicity)保证,这意味着在多线程环境下,volatile变量的读写操作可能会被拆分成多个步骤,导致不可预测的结果。

    在这个问题中,firstsecond 变量应该用来协调三个线程的执行顺序,但是它们并没有达到预期的效果。要解决这个问题,你需要引入额外的同步机制,比如使用java.util.concurrent.locks.Lock接口提供的锁来确保线程安全。

    这里是一个使用ReentrantLock来实现正确同步的示例:

    import java.util.concurrent.locks.ReentrantLock;
    
    class Foo {
        private final ReentrantLock lock1 = new ReentrantLock();
        private final ReentrantLock lock2 = new ReentrantLock();
    
        public void first(Runnable printFirst) throws InterruptedException {
            lock1.lock();
            try {
                printFirst.run();
                lock2.lock();
            } finally {
                lock1.unlock();
            }
        }
    
        public void second(Runnable printSecond) throws InterruptedException {
            lock2.lock();
            try {
                printSecond.run();
                lock2.unlock();
            } finally {
                lock2.unlock();
            }
        }
    
        public void third(Runnable printThird) throws InterruptedException {
            lock2.lock();
            try {
                printThird.run();
                lock2.unlock();
            } finally {
                lock2.unlock();
            }
        }
    }
    

    这段代码中,我们使用了两个ReentrantLock实例:lock1lock2first() 方法获取 lock1 的锁,然后在释放 lock1 之前获取 lock2 的锁。这样就确保了 first()second() 之前执行。类似地,second()third() 都会先获取 lock2 的锁,这使得 second() 总是在 first()third() 之前执行。

    注意,每个方法都在 finally 块中解锁相应的锁,即使在运行过程中发生异常,也能确保锁会被正确释放,防止死锁。

    现在,如果你按照这个修改后的代码运行,你应该能得到期望的输出结果:“firstsecondthird”。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月18日