多线程的参数传递

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

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

比如这个程序:

 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

多线程的参数传递的相关文章

从零开始学习Java多线程(二)

前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处理返回结果,大多情况下,整个过程均是由一条线程执行,排除运行不必要的的偶发性,似乎并不会出现意料之外的结果.而在多线程环境下,在使用线程时需要对线程进行一些必要的初始化,线程对这些数据进行处理后返回结果,由于线程的运行和结束并不可控,线程传参变得复杂起来,本文就以上问题介绍三种常用的传递参数方式.

C# Thread Programming Start

引言 1.理解多线程 2. 线程异步与线程同步 3.创建多线程应用程序 3.1通过System.Threading命名空间的类构建 3.1.1异步调用线程 3.1.2并发问题 3.1.3线程同步 3.2通过委托构建多线程应用程序 3.2.1线程异步 3.2.2线程同步 3.3BackgroundWorker组件 4.总结 引言 随着双核.四核等多核处理器的推广,多核处理器或超线程单核处理器的计算机已很常见,基于多核处理的编程技术也开始受到程序员们普遍关注.这其中一个重要的方面就是构建多线程应用程

linuxc多线程参数传递

#include <stdio.h> #include <pthread.h> struct stu { int age; char *name; char *num; }; void thread1(void) { int i; for(i=0;i<3;i++) { printf("This is a pthread1.\n"); usleep(2); } } //传递多个参数 void thread2(void *data) { struct stu

c/c++ 多线程 参数传递

多线程 参数传递 1,值传递,拷贝一份新的给新的线程.线程1中有个int变量a,在线程1中启动线程2,参数是a的值,这时就会拷贝a,线程1和线程2不共享a. 2,引用传递,不拷贝一份新的给新的线程.线程1中有个int变量a,在线程1中启动线程2,参数是a的引用,这时就不会拷贝a,线程1和线程2共享a.※传递参数时,必须明确指出使用std::ref函数,不写std::ref,编译不过. 3,指针传递,浅拷贝原来的指针给新的线程.线程1中有个指向int变量a的指针,在线程1中启动线程2,参数是a的地

C# 多线程参数传递

1.通过实体类来传递(可以传递多个参数与获取返回值),demo如下: 需要在线程中调用的函数: namespace ThreadParameterDemo { public class FunctionClass { public static string TestFunction(string name, int age) { //内部处理省略 return name + " 的年龄是:" + age; } } } 通过实体来来封装: namespace ThreadParamet

python多线程学习记录

1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start(),启动线程 t.join(),阻塞当前线程,即使得在当前线程结束时,不会退出.会等到子线程结束之后才退出. 如果不加join语句,主线程不会等到子线程结束才结束,但却不会立即杀死该线程. 但是如果添加了SetDaemon(True),如果不加join,则会在主线程结束后马上杀死子线程. 如果join

Spring单实例、多线程安全、事务解析

原文:http://blog.csdn.net/c289054531/article/details/9196053 引言: 在使用Spring时,很多人可能对Spring中为什么DAO和Service对象采用单实例方式很迷惑,这些读者是这么认为的: DAO对象必须包含一个数据库的连接Connection,而这个Connection不是线程安全的,所以每个DAO都要包含一个不同的Connection对象实例,这样一来DAO对象就不能是单实例的了. 上述观点对了一半.对的是“每个DAO都要包含一个

多线程 pthread + NSThread

多线程 pthread + NSThread pthread (C语言) · 规律: C语言中的数据类型一般都是以 _t或者Ref结尾 创建C语言的对象, 一般都用cretae#import <pthread/pthread.h>- (IBAction)btnOnClick:(id)sender { // 1.创建子线程/* 第1个参数:线程代号 (现场对象) 第2个参数:线程的属性 第3个参数:子线程需要执行的操作(调用的方法) void *(*)(void *) 返回值 (*指针名称)参数

Java多线程10:ThreadLocal的作用及使用

ThreadLocal的作用 从上一篇对于ThreadLocal的分析来看,可以得出结论:ThreadLocal不是用来解决共享对象的多线程访问问题的,通过ThreadLocal的set()方法设置到线程的ThreadLocal.ThreadLocalMap里的是是线程自己要存储的对象,其他线程不需要去访问,也是访问不到的.各个线程中的ThreadLocal.ThreadLocalMap以及ThreadLocal.ThreadLocal中的值都是不同的对象. 至于为什么要使用ThreadLoca