網上一個錯誤示例:https://www.cnblogs.com/Simeonwu/p/7881100.html,部分代碼如下:
package com.me.config; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** * Project: me * Package: com.me.config * Date: 2017/11/22 19:30 * Author: Simeon */ class Demo extends Thread { public void run() { Jedis jedis1 = new Jedis(); for (int i=0;i<100;i++){ int num = Integer.parseInt(jedis1.get("num"));// 1: 代碼行1 num = num + 1; // 2: 代碼行2 jedis1.set("num",num+""); System.out.println(jedis1.get("num")); } } } public class test{ public static void main(String... args){ Jedis jedis = new Jedis(); jedis.set("num","1"); new Demo().start(); new Demo().start(); } }
如代碼所示,例如當線程1在代碼行讀取數值為99時候,此時線程2頁執行讀取操作也是99,隨后同時執行num=num+1,之后更新,導致一次更新丟失,這就是這個代碼測試的錯誤之處。所以Redis本身是線程安全的,但是你還需要保證你的業務必須也是線程安全的。
注意:千萬不要以為原子操作是線程安全的,原子操作只能保證命令全執行或者全不執行,並不會保證線程安全操作。例如數據庫中的事務就是原子的,依舊還需要提供並發控制!!!!
原子性操作是否線程安全?
原文:https://stackoverflow.com/questions/14370575/why-are-atomic-operations-considered-thread-safe
1.原子操作是針對訪問共享變量的操作而言的。涉及局部變量訪問的操作無所謂是否原子的。
2.原子操作是從該操作的執行線程以外的線程來描述的,也就是說它只有在多線程環境下才有意義。
原子操作得“不可分割”包括兩層含義
1.訪問(讀、寫)某個共享變量的操作從其執行線程以外的任何線程來看,該操作要么已經執行結束要么尚未發生,
即其他線程不會“看到”該操作執行了部分的中間效果。
2.訪問同一組共享變量的原子操作是不能夠被交錯的。
此原子性與數據庫原子性有區別:最主要區別是數據庫的原子性,可以被其他線程看見中間狀態,否則就不會有隔離級別的事了。