QuoteTest(引用对象技巧)
1 import java.util.ArrayList;
2 import java.util.HashMap;
3 import java.util.List;
4 import java.util.Map;
5
6 /**
7 * Created by robin on 2016/4/13.
8 * 引用型对向操作总结:
9 * 1.被引用的对象,值改变时,会直接改变引用源的值;
10 * 2.当引用的对象,改变其引用源时,对其操作,只会改变新的引用源的值,并不会影响之前的引用源的值
11 * 3.从map中获取的引用不存在时,需要将新的引用put到map中,map中该位置的值,才会被引入
12 * @author robin
13 */
14 public class QuoteTest {
15
16 public static void main(String args[]){
17 Map<String,List<String>> map = new HashMap<String, List<String>>();
18 for (int i =0;i< 5;i++){
19 List<String> datalist = new ArrayList<String>();
20 for (int j=0;j<10;j++){
21 datalist.add(i*10+""+j);
22 }
23 map.put(""+i,datalist);
24 }
25 for (List<String> list:map.values()){
26 System.out.println(listToString(list));
27 }
28 System.out.println("----------分隔线1-----------");
29 List<String> tempList = map.get("3");
30 tempList.add("avc");
31 tempList.remove("300");
32 for (List<String> list:map.values()){
33 System.out.println(listToString(list));
34 }
35 System.out.println("----------分隔线2-----------");
36 List<String> tempList2 = map.get("2");//tempList 获得map中 key为2的引用
37 List<String> replaceList = new ArrayList<String>();
38 tempList2 = replaceList;////tempList 获得其他list的引用,失去map中 key为2的引用,此时对templist2做任何操作,影响的时replaceList引用的区域
39 tempList2.add("replaceList的值被改变");
40 for (List<String> list:map.values()){
41 System.out.println(listToString(list));
42 }
43 System.out.println("replaceList的值:"+listToString(replaceList));
44 System.out.println("----------分隔线3-----------");
45 List<String> tempList3 = map.get("2");
46 tempList3 = replaceList;
47 map.put("2",tempList3);
48 for (List<String> list:map.values()){
49 System.out.println(listToString(list));
50 }
51 System.out.println("----------分隔线4-----------");
52 List<String> notExistList = map.get("5");
53 if(notExistList == null){
54 notExistList = new ArrayList<String>();
55 }
56 notExistList.add("第5行数据添加进来...");
57 for (List<String> list:map.values()){
58 System.out.println(listToString(list));
59 }
60 System.out.println("----------分隔线5-----------");
61 List<String> notExistList2 = map.get("6");
62 if(notExistList2 == null){
63 notExistList2 = new ArrayList<String>();
64 }
65 notExistList2.add("第6行数据添加进来...");
66 map.put("6",notExistList2);
67 for (List<String> list:map.values()){
68 System.out.println(listToString(list));
69 }
70 System.out.println("----------分隔线5-----------");
71
72 Map<String,Map<String,String>> mapOne = new HashMap<String, Map<String, String>>();
73 String keyss = "mapTest";
74 Map<String,String> mapTwo = new HashMap<String, String>();
75 mapOne.put(keyss,mapTwo);
76 System.out.println("mapOne的数据:" + mapToString(mapOne));
77 System.out.println("----------分隔线6-----------");
78 mapTwo.put("aaa", "aaav");
79 mapTwo.put("bbb", "bbbv");
80 mapTwo.put("ccc","cccv");
81 System.out.println("mapOne的数据:"+mapToString(mapOne));
82 System.out.println("----------分隔线7-----------");
83 }
84
85 private static String listToString(List<String> list){
86 StringBuilder sb = new StringBuilder("");
87 for (String s:list){
88 sb.append("["+s+"] ");
89 }
90 return sb.toString();
91 }
92
93 private static String mapToString(Map<?,?> map){
94 StringBuilder sb = new StringBuilder("");
95 for(Map.Entry entry:map.entrySet()){
96 sb.append("[key:"+entry.getKey()+";value:"+entry.getValue()+"]");
97 }
98 return sb.toString();
99 }
100
101 }
---------------------
引用对象易产生的bug:
2016.05.11
关于引用对象,使用不恰当,很容易给自己挖坑,产生非常严重的bug,进而导致整个系统实际业务的崩溃,而且这种bug很难被查出来。(如果日志记录不够详细,分析不够彻底,要找出这种bug,只能靠上帝保佑)
下面先上bug 代码 demo
1 import java.util.Iterator;
2 import java.util.List;
3 import java.util.Vector;
4
5 /**
6 * Created by robin on 2016/5/11.
7 *
8 * @author robin
9 */
10 public class QuoteBugDemo {
11
12 private static List<Integer> publicNums = new Vector<Integer>();
13
14 public static void main(String args[]) throws InterruptedException {
15 initPublicNums();//初始化公共数据源
16
17 timeTask(1);//模拟执行定时任务1
18
19 timeTask(2);//模拟执行定时任务2
20
21 }
22
23
24 private static void initPublicNums(){
25 for (int i =0;i < 10;i++){
26 publicNums.add(i);
27 }
28 }
29
30 /**
31 * 这块代码模拟的逻辑:
32 * 1.每天获取配置好10个的数据源;
33 * 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
34 * 3.从当天的带同步数据源list删除已经同步的数据;
35 * @param mark
36 * @throws InterruptedException
37 */
38 private static void timeTask(int mark) throws InterruptedException {
39 final long start = System.currentTimeMillis();//程序开始运行时间
40 //每天待同步数据源
41 List<Integer> dataSources = publicNums;
42 StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
43 for (Integer i:dataSources){
44 sb.append(i+",");
45 }
46 sb.append("]");
47 System.out.println("日志【"+sb.toString()+"】");
48 while(true){
49 long seconds = (System.currentTimeMillis() - start) / 1000;
50 if(seconds > 15l){
51 System.out.println("运行超过限定时间:15秒,退出");
52 break;
53 }
54 Iterator<Integer> ite = dataSources.iterator();
55 while (ite.hasNext()){//
56 int dataSource = ite.next();
57 boolean flag = isOk(dataSource);
58 if(flag){//数据源数据已准备好
59 System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
60 ite.remove();//待同步数据源删除该数据源
61 }
62 }
63 if(dataSources.size() != 0){
64 Thread.sleep(1000);
65 }else{
66 break;
67 }
68 }
69 System.out.println("定时任务mark["+mark+"]已经执行完毕");
70 }
71
72 /**
73 * 模拟检查数据源是否OK
74 * @param dataSource
75 * @return
76 */
77 private static boolean isOk(int dataSource){
78 if(dataSource%2 == 0){
79 return true;
80 }
81 return false;
82 }
83
84
85 }
执行结果:
1 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】 2 对数据源:0进行数据处理。 3 对数据源:2进行数据处理。 4 对数据源:4进行数据处理。 5 对数据源:6进行数据处理。 6 对数据源:8进行数据处理。 7 运行超过限定时间:15秒,退出 8 定时任务mark[1]已经执行完毕 9 日志【mark(2);公共数据源数目:5;数据源列表[1,3,5,7,9,]】 10 运行超过限定时间:15秒,退出 11 定时任务mark[2]已经执行完毕
定时任务2,执行的时候,数据源只剩1,3,5,7,9。
改进方案:将公共数据源保护起来,仅提供公共数据源的副本:shallow copy和deep copy
核心代码:
1 /**
2 * 改进方案1:获取公共数据源对象的副本
3 * shallow copy:list中 元素引用 仍然是相同的
4 * @return
5 */
6 private static List<Integer> getPublicNums(){
7 List<Integer> clone = new ArrayList<Integer>(publicNums);
8 return clone;
9 }
改进后全部代码:
1 import java.util.ArrayList;
2 import java.util.Iterator;
3 import java.util.List;
4 import java.util.Vector;
5
6 /**
7 * Created by robin on 2016/5/11.
8 *
9 * @author robin
10 */
11 public class QuoteBugDemo {
12
13 private static List<Integer> publicNums = new Vector<Integer>();
14
15 public static void main(String args[]) throws InterruptedException {
16 initPublicNums();//初始化公共数据源
17
18 timeTask(1);//模拟执行定时任务1
19
20 timeTask(2);//模拟执行定时任务2
21
22 }
23
24
25 private static void initPublicNums(){
26 for (int i =0;i < 10;i++){
27 publicNums.add(i);
28 }
29 }
30
31 /**
32 * 改进方案1:获取公共数据源对象的副本
33 * shallow copy:list中 元素引用 仍然是相同的
34 * @return
35 */
36 private static List<Integer> getPublicNums(){
37 List<Integer> clone = new ArrayList<Integer>(publicNums);
38 return clone;
39 }
40
41 /**
42 * 这块代码模拟的逻辑:
43 * 1.每天获取配置好10个的数据源;
44 * 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
45 * 3.从当天的带同步数据源list删除已经同步的数据;
46 * @param mark
47 * @throws InterruptedException
48 */
49 private static void timeTask(int mark) throws InterruptedException {
50 final long start = System.currentTimeMillis();//程序开始运行时间
51 //每天待同步数据源
52 List<Integer> dataSources = getPublicNums();//改进方案1
53 StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
54 for (Integer i:dataSources){
55 sb.append(i+",");
56 }
57 sb.append("]");
58 System.out.println("日志【"+sb.toString()+"】");
59 while(true){
60 long seconds = (System.currentTimeMillis() - start) / 1000;
61 if(seconds > 15l){
62 System.out.println("运行超过限定时间:15秒,退出");
63 break;
64 }
65 Iterator<Integer> ite = dataSources.iterator();
66 while (ite.hasNext()){//
67 int dataSource = ite.next();
68 boolean flag = isOk(dataSource);
69 if(flag){//数据源数据已准备好
70 System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
71 ite.remove();//待同步数据源删除该数据源
72 }
73 }
74 if(dataSources.size() != 0){
75 Thread.sleep(1000);
76 }else{
77 break;
78 }
79 }
80 System.out.println("定时任务mark["+mark+"]已经执行完毕");
81 }
82
83 /**
84 * 模拟检查数据源是否OK
85 * @param dataSource
86 * @return
87 */
88 private static boolean isOk(int dataSource){
89 if(dataSource%2 == 0){
90 return true;
91 }
92 return false;
93 }
94
95
96 }
执行结果:
1 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】 2 对数据源:0进行数据处理。 3 对数据源:2进行数据处理。 4 对数据源:4进行数据处理。 5 对数据源:6进行数据处理。 6 对数据源:8进行数据处理。 7 运行超过限定时间:15秒,退出 8 定时任务mark[1]已经执行完毕 9 日志【mark(2);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】 10 对数据源:0进行数据处理。 11 对数据源:2进行数据处理。 12 对数据源:4进行数据处理。 13 对数据源:6进行数据处理。 14 对数据源:8进行数据处理。 15 运行超过限定时间:15秒,退出 16 定时任务mark[2]已经执行完毕
