创建多线程的回调函数时,传入的参数会被当做一个引用保存起来,即使这个参数没有明显的对应到一个变量上。
即使后来传入的参数指向了其他对象,但是多线程保存的引用是不会变的。
比如这个程序:
1 @Test 2 public void testMultiThread() throws InterruptedException 3 { 4 final List<StringBuilder> strs = new ArrayList<StringBuilder>(); 5 6 strs.add(new StringBuilder("1")); 7 strs.add(new StringBuilder("2")); 8 strs.add(new StringBuilder("3")); 9 strs.add(new StringBuilder("4")); 10 11 final List<Callable<String>> tasks = new ArrayList<Callable<String>>(); 12 for (final StringBuilder str : strs) 13 { 14 tasks.add(new Callable<String>() 15 { 16 public String call() throws Exception 17 { 18 System.out.println(str.append("Hello").append("@").append(str.hashCode())); 19 return str + "Hello"; 20 } 21 }); 22 } 23 24 for (int i = 0; i < strs.size(); i++) 25 { 26 strs.get(i).append("new"); 27 } 28 29 for (StringBuilder str : strs) 30 { 31 System.out.println(str.hashCode()); 32 } 33 34 final ExecutorService executorService = Executors.newFixedThreadPool(5); 35 executorService.invokeAll(tasks);
不出意外,因为执行多线程之前,引用指向并未发生变化,所以在多线程外做的修改,会影响到后来的调用。
4895754 7477605 14765756 33038931 [email protected] [email protected] [email protected] [email protected]
如果将参数从StringBuilder改为String,结果将发生变化,因为String是不能修改的,执行附加的时候实际上是生成了一个新的对象。
但是对于已经创建好的多线程任务来说,他们保存的依然是以前的引用。
@Test public void testMultiThread2() throws InterruptedException { final List<String> strs = new ArrayList<String>(); strs.add("1"); strs.add("2"); strs.add("3"); strs.add("4"); final List<Callable<String>> tasks = new ArrayList<Callable<String>>(); for (final String str : strs) { tasks.add(new Callable<String>() { public String call() throws Exception { System.out.println(str + "Hello" + "@" + str.hashCode()); return str + "Hello"; } }); } for (int i = 0; i < strs.size(); i++) { strs.set(i, "hello"); } for (String str : strs) { System.out.println(str + "@" + str.hashCode()); } final ExecutorService executorService = Executors.newFixedThreadPool(5); executorService.invokeAll(tasks); }
多线程内的参数不受外部变化影响:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
这个例子中,即使在创建了多线程任务之后将strs数组的内容全部清空,也不会对结果造成影响,因为多线程保存了原始的引用。
对于原始类型,则多线程任务保存了他们的值,也不受外部变化的影响。
时间: 2024-10-15 16:56:28