先贴上代码:
import java.util.ArrayList;
public class main {
public static void main(String[] args) {
HandlerTest handlerTest = new HandlerTest();
ArrayList<Integer> arrayList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
arrayList.add(i);
}
handlerTest.setList(arrayList);
ThreadTest threadTest = new ThreadTest(handlerTest);
threadTest.start();
new Thread(()->{
ArrayList<Integer> list1;
while (true){
list1 = handlerTest.getList();
try {
System.out.println("还没死循环。。。。。" + "本地的list" + list1.hashCode() + " 传递的list " + handlerTest.getList().hashCode());
}catch (Exception e){
}
while (list1.size() == 0){
System.out.println("本地的list "+list1.hashCode()+ " 传递的list " + handlerTest.getList().hashCode());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
import java.util.ArrayList;
public class HandlerTest {
private volatile ArrayList<Integer> list = new ArrayList<>();
public ArrayList<Integer> getList() {
return list;
}
public void setList(ArrayList<Integer> list) {
this.list = list;
}
}
import java.lang.reflect.Array;
import java.util.ArrayList;
public class ThreadTest extends Thread{
private HandlerTest ht;
public ThreadTest(HandlerTest ht){
this.ht = ht;
}
@Override
public void run() {
int i = 0;
while (true){
this.ht.getList().add(i);
System.out.println(i);
i++;
if (i % 20 == 0) {
System.out.println(" "+i);
this.ht.getList().clear();
this.ht.setList(new ArrayList<>());
this.ht.getList().clear();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
遇到的问题就是当ThreadTest 中的代码运行到了i==20的时候就会导致main函数哪里出现死循环导致,后续无法继续运行。
这段代码是我的热运行项目中的一段衍生代码,用来检测有无新的代码。
出现了问题后就将其摘出来debug,最后发现了问题的所在。
先说结果:
结果是这样子的
list1-》list-》实际的内存,然后如果实际的内存中没有数据的话恰巧list1检测到size为空,那么就会进入死循环。那么后续的list1就不会得到更新。所以造成了死循环,究其原因是因为在循环中list1没有及时地得到更新导致的。
原因
也就是结果里提到的但是这个还需要验证一下,具体的验证,博主使用的是hashcode来实现的:
- …
- 还没死循环。。。。。本地的list377310269 传递的list 377310269
还没死循环。。。。。本地的list377310269 传递的list 377310269
还没死循环。。。。。本地的list377310269 传递的list 377310269
还没死循环。。。。。本地的list377310269 传递的list 377310269
还没死循环。。。。。本地的list377310269 传递的list 377310269
还没死循环。。。。。本地的list377310269 传递的list 377310269
还没死循环。。。。。本地的list377310269 传递的list 377310269
20
还没死循环。。。。。本地的list377310269 传递的list 377310269
本地的list 1 传递的list 1
本地的list 1 传递的list 1
本地的list 1 传递的list 1
20
本地的list 1 传递的list 51
21
本地的list 1 传递的list 49684
22
本地的list 1 传递的list 49684
23
本地的list 1 传递的list 1540227
…
…
可以看到在i达到了20是的时候出现了死循环,在这之前list1的hashcode和list的hashcode是一样的,之后的就不一样了。
由此可以验证,list1指向的是真实的地址,list指向的也是真实的地址。但是每一次list1的地址的更新都是依靠list的赋值来实现地址的更新所以问题就是在这里出现的,一旦list1不能够被list正常的更新,那么就会出现问题。
而在系循环中list1·是得不到更新的。
解决办法
- 在循环中执行更新语句,如:
while (list1.size() == 0){
System.out.println("本地的list "+list1.hashCode()+ " 传递的list " + handlerTest.getList().hashCode());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
/添加的代码
list1 = handlerTest.getList();
}
2.不使用局部变量,如:
while (handlerTest.getList().size() == 0){
System.out.println("本地的list "+list1.hashCode()+ " 传递的list " + handlerTest.getList().hashCode());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}