「非線程安全」其實會在多個線程對同一個對象中的實例變量進行併發訪問時發生,產生的後果就是「髒讀」,也就是渠道的數據實際上是被更改過的。而「線程安全」就是得到的實例變量的值是通過同步處理的,不會出現髒讀現象。java
「非線程安全」問題存在於「實例變量」中,若是是方法內部的私有變量,則不存在「非線程安全」問題,所得的結果也就是「線程安全」的了。安全
import java.util.HashMap; import java.util.Map; public class HasSelfPrivateNum { //private int num = 0; public void add(String username){ Map<Integer,Integer> m = new HashMap<Integer,Integer>(); try { int num = 0; if (username.equals("a")){ num = 100; System.out.println("a set over"); Thread.sleep(1000); for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("A賦值前--K: "+mm.getKey()+",V: "+mm.getValue()); for(int i=0;i<1000;i++){ m.put(i, i+10); } for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("A賦值後--K: "+mm.getKey()+",V: "+mm.getValue()); }else { num = 200; System.out.println("b set over"); for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("B賦值前--K: "+mm.getKey()+",V: "+mm.getValue()); for(int i=0;i<1000;i++){ m.put(i, i+20); } for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("B賦值後-K: "+mm.getKey()+",V: "+mm.getValue()); } System.out.println("username=" + username + ", num=" + num); }catch (InterruptedException e){ e.printStackTrace(); } } }
線程a併發
public class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef){ super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.add("a"); } }
線程bide
public class ThreadB extends Thread{ private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef){ super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.add("b"); } }
執行主線程this
public class Run { public static void main(String[] args) { HasSelfPrivateNum numRf = new HasSelfPrivateNum(); ThreadA threadA = new ThreadA(numRf); threadA.start(); ThreadB threadB = new ThreadB(numRf); threadB.start(); } }
結果以下:spa
a set over b set over B賦值後-K: 0,V: 20 B賦值後-K: 1,V: 21 B賦值後-K: 2,V: 22 B賦值後-K: 3,V: 23 B賦值後-K: 4,V: 24 B賦值後-K: 5,V: 25 B賦值後-K: 6,V: 26 B賦值後-K: 7,V: 27 B賦值後-K: 8,V: 28 B賦值後-K: 9,V: 29 B賦值後-K: 10,V: 30 B賦值後-K: 11,V: 31 B賦值後-K: 12,V: 32 **** username=b, num=200 A賦值後--K: 0,V: 10 A賦值後--K: 1,V: 11 A賦值後--K: 2,V: 12 A賦值後--K: 3,V: 13 A賦值後--K: 4,V: 14 A賦值後--K: 5,V: 15 A賦值後--K: 6,V: 16 A賦值後--K: 7,V: 17 A賦值後--K: 8,V: 18 A賦值後--K: 9,V: 19 A賦值後--K: 10,V: 20 A賦值後--K: 11,V: 21 A賦值後--K: 12,V: 22 A賦值後--K: 13,V: 23 A賦值後--K: 14,V: 24 A賦值後--K: 15,V: 25 A賦值後--K: 17,V: 27
若是多個線程共同訪問一個對象中的實例變量,則有可能出現「非線程安全」問題。用線程訪問的對象中若是有多個實例變量,則運行的結果有可能出現交叉的狀況。
將上面的代碼作以下更改:線程
import java.util.HashMap; import java.util.Map; public class HasSelfPrivateNum { private int num = 0; Map<Integer,Integer> m = new HashMap<Integer,Integer>(); public void add(String username){ try { // int num = 0; if (username.equals("a")){ num = 100; System.out.println("a set over"); Thread.sleep(1000); for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("A賦值前--K: "+mm.getKey()+",V: "+mm.getValue()); for(int i=0;i<1000;i++){ m.put(i, i+10); } for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("A賦值後--K: "+mm.getKey()+",V: "+mm.getValue()); }else { num = 200; System.out.println("b set over"); for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("B賦值前--K: "+mm.getKey()+",V: "+mm.getValue()); for(int i=0;i<1000;i++){ m.put(i, i+20); } for(Map.Entry<Integer, Integer> mm : m.entrySet()) System.out.println("B賦值後-K: "+mm.getKey()+",V: "+mm.getValue()); } System.out.println("username=" + username + ", num=" + num); }catch (InterruptedException e){ e.printStackTrace(); } } }
運行結果以下:code
a set over b set over B賦值後-K: 0,V: 20 B賦值後-K: 1,V: 21 B賦值後-K: 2,V: 22 B賦值後-K: 3,V: 23 B賦值後-K: 4,V: 24 B賦值後-K: 5,V: 25 B賦值後-K: 6,V: 26 B賦值後-K: 7,V: 27 B賦值後-K: 8,V: 28 B賦值後-K: 9,V: 29 B賦值後-K: 10,V: 30 **** username=b, num=200 A賦值前--K: 0,V: 20 A賦值前--K: 1,V: 21 A賦值前--K: 2,V: 22 A賦值前--K: 3,V: 23 A賦值前--K: 4,V: 24 A賦值前--K: 5,V: 25 A賦值前--K: 6,V: 26 A賦值前--K: 7,V: 27 A賦值前--K: 8,V: 28 A賦值前--K: 9,V: 29 A賦值前--K: 10,V: 30 A賦值前--K: 11,V: 31 ***** A賦值前--K: 966,V: 986 A賦值前--K: 965,V: 985 A賦值前--K: 964,V: 984 A賦值後--K: 0,V: 10 A賦值後--K: 1,V: 11 A賦值後--K: 2,V: 12 A賦值後--K: 3,V: 13 A賦值後--K: 4,V: 14 A賦值後--K: 5,V: 15 A賦值後--K: 6,V: 16 A賦值後--K: 7,V: 17 **** A賦值後--K: 960,V: 970 A賦值後--K: 967,V: 977 A賦值後--K: 966,V: 976 A賦值後--K: 965,V: 975 A賦值後--K: 964,V: 974 username=a, num=200