java数据同步陷阱

并发,我的理解就是同时运行多个程序。同时,难以避免的就是数据的同步问题,如果数据同步问题处理不好就很容易造成程序出现bug,当然,对于其造成的危害,不加详述。

首先,来看一个简单的例子,当然,这个例子也并非是我发现的。

public class StopTread {
    private static boolean stopRequested;
    
    static Thread backgroundThread = new Thread(new Runnable() {
         
        public void run() {
            int i = 0;
            while(!stopRequested)
            {
                i++;
            }
        }
    });
    
    public static void main(String[] args) throws InterruptedException
    {
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

造成这个问题的原因在于当主线程修改了stopRequested变量后,后台线程并没有及时的读取到最新的值,因此,造成了后台线程会一直运行下去。代码内容很容易理解,就是通过一个变量来控制线程的停止与运行而已。当stopRequested被主线程设置为true时,后台线程就终止运行。但是,这个程序中并没有对stopRequested做数据同步处理,这就造成了数据的不安全性,当然,并不是在所有情况都能发生这个数据的不安全性的。但至少理论上是存在,同时,我也花费了很长的时间,模拟出了这个不安全性的存在。

根据相关资料解释其原因为:

while(!stopRequested)
{
    i++;
}

被优化成了:

if(!stopRequested)
    while(true)
        i++;

也正是由于这个优化导致了程序无法前进执行。

对于解决这个问题的方法有两种:其一是通过锁机制,其二是通过volatile修饰符。

方法一:

public class StopTread {
    private static boolean stopRequested;
    
    static Thread backgroundThread = new Thread(new Runnable() {
         
        public void run() {
            int i = 0;
            while(!stopRequested())
            {
                i++;
            }
        }
    });
    
    private static synchronized void requestStop()
    {
        stopRequested = true;
    }
    
    
    private static synchronized boolean stopRequested()
    {
        return stopRequested;
    }
    
    public static void main(String[] args) throws InterruptedException
    {
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        requestStop();
    }
}

  可以发现,写方法和读方法都被同步了,只同步写方法是不能实现,如果没有对读和写方法都进行同步的话,同步是不会起作用的。

方法二:

public class StopTread {
    private static volatile boolean stopRequested;
    
    static Thread backgroundThread = new Thread(new Runnable() {
         
        public void run() {
            int i = 0;
            while(!stopRequested)
            {
                i++;
            }
        }
    });
   
    public static void main(String[] args) throws InterruptedException
    {
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

Volatile的修饰符不执行互斥访问,但是可以保证一个县城在读取该域的时候就讲看到最近刚刚被写入的值

原文地址:https://www.cnblogs.com/woniu4/p/5361816.html