方法参数和局部变量是线程安全的

时间:2014-04-09 08:28:59

标签: java multithreading thread-safety

任何人都可以确认以下声明吗?

  

方法在方法中声明的参数和局部变量是Thread   安全;两者都是Thread的每次调用都是独占的。

     

另一方面,全局变量是共享的。

例如

class MyThread implements Runnable{

    int _tmp = 10;      //SHARED BETWEEN t1, t2, t3, and so on

    public void run(){

        testThreadConcurrency(arg); // arg  is EXCLUSIVE FOR ALL invocation of testThreadConcurrency
    }

    public void testThreadConcurrency (int num){

        int tmp = 10;   //EXCLUSIVE FOR ALL invocation of testThreadConcurrency()

    }
}


public static void main(String[] args) {
        // TODO Auto-generated method stub

        MyThread _runn = new MyThread();

        Thread t1 = new Thread(_runn,"t1");
        Thread t2 = new Thread(_runn,"t2");
        Thread t3 = new Thread(_runn,"t3");
        t1.start();
        t2.start();             
        t3.start()
}

**

  

请检查以下程序的输出,以证明Global   变量是SHARED

**

public class ThreadDemo {

    static Object _lock = new Object();

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        MyThread _runn = new MyThread();

        Thread t1 = new Thread(_runn,"t1");
        Thread t2 = new Thread(_runn,"t2");
        Thread t3 = new Thread(_runn,"t3");
        t1.start();
        try {Thread.sleep(300);} catch (InterruptedException e1) {}
        t2.start(); 
        try {Thread.sleep(300);} catch (InterruptedException e1) {}
        t3.start(); 

        try {Thread.sleep(300);} catch (InterruptedException e1) {}
        synchronized(ThreadDemo._lock){ThreadDemo._lock.notify();}

        try {Thread.sleep(300);} catch (InterruptedException e1) {}
        synchronized(ThreadDemo._lock){ThreadDemo._lock.notify();}


        try {Thread.sleep(300);} catch (InterruptedException e1) {}
        synchronized(ThreadDemo._lock){ThreadDemo._lock.notify();}


    }

}

class MyThread implements Runnable{

    int _tmp = 10;

    public void run(){

        testTestConcurrency();
    }

    public void testTestConcurrency(){

        if(Thread.currentThread().getName().equals("t2"))
        {
            _tmp = 20;          
        }

        synchronized(ThreadDemo._lock){try {ThreadDemo._lock.wait();} catch (InterruptedException e) {}}

        System.out.println("_tmp = "+_tmp+"|"+Thread.currentThread().getName());


    }
}

3 个答案:

答案 0 :(得分:1)

小心!参数和变量不是对象。假设几个线程各自进入一个操作List的方法:

public Foo mumbler(List<Bar> barList) {
    ...
}

方法的每次调用都有自己唯一的barList 变量。任何其他线程都无法访问它,但是如果所有这些变量都持有对同一个List对象的引用,那么如果它们不相互排斥或阻止它,那么线程仍然可以(并且可能会)破坏List。通过其他方式。

编辑:

  

我忘记了Java传递原语作为CallByValue但是在引用的情况下使用了CallByReference ....

更好的说法是,Java按值传递对象引用

在C ++中你可以这样写:(并不是说你想要来写它: - )

pushValueOnStack(my_type_t value, struct node &top) {
    struct node new_node = malloc(sizeof(*new_node));
    new_node->value = value;
    new_node->next = top;
    top = new_node;
}

如果您有一个局部变量 myStack ,并且您调用了pushValueOnStack(someValue, myStack),,它实际上会更改您的局部变量以指向堆栈的新顶级节点。这是由参考号召集的。这在Java中永远不会发生。

答案 1 :(得分:0)

不完全

T1的_tmp未与T2的_tmp共享,因为它们是不同的MyThread个实例(不是类'变量,而是实例的变量)。

实际上,每次创建线程时都要重新实例化整个类:

new MyThread

如果属性实际上是类变量,则会有所不同:

static int _tmp = 10;

在这种情况下,您可能需要一些同步机制(synchronized阻止或volatile关键字或其他任何适应该情况的方法)

我会把它改为:

  

方法在方法中声明的参数和局部变量是Thread   安全;两者都是Thread的每次调用都是独占的。

     

但是,处理一个或多个全局变量的任何类的同一实例   在击中线程中分享那些。

最佳做法是避免线程之间的最大共享实例,以避免同步所有内容(只要性能/内存不会受到太大伤害)。

因此,您的代码段遵循最佳做法:)

-----------关于您添加的代码SNIPPET的评论--------------

MyThread _runn = new MyThread();  //you are using the same instance here ! delete this line

因此,在这种情况下,如果在声明每个线程时重用此实例,则该属性将为share:

Thread t1 = new Thread(_runn,"t1");
Thread t2 = new Thread(_runn,"t2");
Thread t3 = new Thread(_runn,"t3");

仅用以下方式替换:

Thread t1 = new Thread(new MyThread(), "t1"); //a new MyThread instance for each thread !
Thread t2 = new Thread(new MyThread(), "t2");
Thread t3 = new Thread(new MyThread(), "t3");

将输出(如预期:)):

_tmp = 10|t3
_tmp = 10|t1
_tmp = 20|t2

答案 2 :(得分:0)

  

在方法内声明的方法参数和局部变量是线程安全的;两者都是Thread的每次调用都是独占的。

方法的每次调用。没有“调用线程”这样的东西,如果存在,则没有足够的包容性。 “调用方法”包括递归的情况以及多线程的情况。

  

另一方面,全局变量是共享的。