多线程的参数传递

创建多线程的回调函数时,传入的参数会被当做一个引用保存起来,即使这个参数没有明显的对应到一个变量上。

即使后来传入的参数指向了其他对象,但是多线程保存的引用是不会变的。

比如这个程序:

 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
2newHello@7477605
1newHello@4895754
3newHello@14765756
4newHello@33038931

如果将参数从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);

    }

  

多线程内的参数不受外部变化影响:

hello@99162322
hello@99162322
hello@99162322
hello@99162322
1Hello@49
3Hello@51
4Hello@52
2Hello@50

这个例子中,即使在创建了多线程任务之后将strs数组的内容全部清空,也不会对结果造成影响,因为多线程保存了原始的引用。

对于原始类型,则多线程任务保存了他们的值,也不受外部变化的影响。

原文地址:https://www.cnblogs.com/humc/p/5104220.html