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