今天写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); } }