“非线程安全”其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”,也就是渠道的数据实际上是被更改过的。而“线程安全”就是得到的实例变量的值是通过同步处理的,不会出现脏读现象。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