synchronized双重校验问题

  今天写synchronized用例的时候,两个线程共享一个对象数据,当操作i的时候,在同步代码块外面判断了一次i<100,但是每一次跑,都会出现i=100,的情况。此时我想起了单例模式的双重校验锁,为什么要判断两次呢?因为可能出现线程1和线程2,在i=99的时候,同时判断了一次,都进到了for循环里面,此时线程1进入同步代码块,线程2进如阻塞队列。当线程1时间片用完,但是代码块并没有执行完。此时,线程2也满足if条件进入同步代码块,之后就会出现线程1和线程2都对i进行了加1,就输出i = 100(同理·,如果三个线程则可能出现101的情况),所以要在同步代码块中再加一次判断,判断i的值

  synchronized代码块使用起来比synchronized方法要灵活得多。因为也许一个方法中只有一部分代码只需要同步,如果此时对整个方法用synchronized进行同步,会影响程序执行效率。而使用synchronized代码块就可以避免这个问题,synchronized代码块可以实现只对需要同步的地方进行同步

import java.util.ArrayList;

/**
 * @Classname DoubleChecking
 * @Description TODO
 * @Date 2020/7/21 13:20
 * @Created by Fearless
 */
public class DoubleChecking {
    public class Data{
        private ArrayList<Integer> arr = new ArrayList<>();
        private Integer i ;
        public void insert(){
            for (i = 0 ; i < 100 ; ++i){
                synchronized (this){
                    //再次校验避免阻塞线程改变i值
                    if (i < 100){
                        if (!arr.contains(i)){
                            arr.add(i);
                            System.out.println(Thread.currentThread().getName()+"正在插入"+i);
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        DoubleChecking doubleChecking = new DoubleChecking();
        Data data = doubleChecking.new Data();
        new Thread(() -> data.insert(),"t1").start();
        new Thread(() -> data.insert(),"t2").start();
        Thread.sleep(3000);
    }
}
原文地址:https://www.cnblogs.com/skyblue123/p/13354779.html