别翻了,成员变量和局部变量在多线程中的使用,看这篇就够了

Posted 来老铁干了这碗代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了别翻了,成员变量和局部变量在多线程中的使用,看这篇就够了相关的知识,希望对你有一定的参考价值。

一. 成员变量和局部变量的区别

  1. 在类中的位置不同
    成员变量:在类中方法外面
    局部变量:在方法或者代码块中,或者方法的声明上(即在参数列表中)
  2. 在内存中的位置不同
    成员变量:在堆中(方法区中静态区),成员变量属于对象,对象进堆内存
    局部变量:在栈中,局部变量属于方法,方法进栈内存
  3. 生命周期不同
    成员变量:随着对象的创建而存在,随着对象的消失而消失
    局部变量:随着方法的调用或代码块的执行而存在,随着方法的调用完毕或者代码块的执行完毕而消失
  4. 初始值
    成员变量:有默认初始值
    局部变量:没有默认初始值,使用前需赋值
  5. 注意:
    成员变量和局部变量的重名问题,就近原则;
    可以使用this关键字区分,this.string指的是类中的成员变量,而不是方法内部的。

代码示例:

public class test 
    public static void main(String[] args) 
        int a = 3;          // 这个是成员变量
        Thread thread = new Thread(() -> 
            int b = 4;      // 这是一个局部变量
        );
        thread.start();
    

二. 多线程中修改调用成员变量


当两个或以上线程访问该对象的成员变量时,因为成员变量是属于对象的,所以两个线程共用一份成员变量,也就是说,当一个线程对成员变量的值做出改变时,是对其他线程是有影响的。

如果一定要使用成员变量, 可以将变量设置为static静态值或者是AtomicInteger原子值, 但这样会造成混乱, 以static类型为例:

public class test 
    static int i = 0;
    public static void main(String[] args) throws Exception 
        Thread thread1 = new Thread(() -> 
            for (i = 0; i < 50; i++) 
                System.out.print(i + " ");
            
        );
        thread1.start();

        Thread thread2 = new Thread(() -> 
            for (i = 0; i < 50; i++) 
                System.out.print(i + " ");
            
        );
        thread2.start();
    


输出:
0 1 2 3 4 5 6 1 1 3 4 5 6 7 2 8 10 11 12 13 14 15 9 17 18 19 16 20 22
23 21 25 26 27 28 29 30 31 32 33 34 35 36 24 38 39 40 41 42 43 44 45 
46 37 48 49 47

我们发现,本来应该输出两次0-50的数字,而结果输出是乱码,也验证了我们的观点:多线程中,某线程调用并修改成员变量会对其他线程产生影响。

当然,如果我们只调用成员变量,并不修改,是可以的。 代码如下:

public class test 
    public static void main(String[] args) throws Exception 
        int i = 50;
        Thread thread1 = new Thread(() -> 
            for (int i1 = 0; i1 < i; i1++) 
                System.out.print(i1 + " ");
            
        );
        thread1.start();

        Thread thread2 = new Thread(() -> 
            for (int i1 = 0; i1 < i; i1++) 
                System.out.print(i1 + " ");
            
        );
        thread2.start();
    


输出:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0 17 18 1 2 3 4 5 6 7 8 9 10
11 19 12 13 14 15 16 17 18 19 20 20 21 22 23 24 25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 21 22 23 24 25 26 27
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 

可以看到,这里会输出两次0-50的乱序数组,是可行的。

有没有什么方法既可以调用并修改成员变量,又不受其他线程影响呢?


我们可以将成员变量赋值多份,并且将其更改为static类型,或AtoimcInteger类型,这样,多份成员变量就会存放在不同的地址里,接下来,每一个线程调用不同的成员变量即可。 以AtomicInteger类型的成员变量为例,代码如下:

public class test 
    public static void main(String[] args) throws Exception 
        int i = 50;

        AtomicInteger i1 = new AtomicInteger(i);
        Thread thread1 = new Thread(() -> 
            for (i1.set(0); i1.get() < 50; i1.getAndIncrement()) 
                System.out.print(i1 + " ");
            
        );
        thread1.start();

        AtomicInteger i2 = new AtomicInteger(i);
        Thread thread2 = new Thread(() -> 
            for (i2.set(0); i2.get() < 50; i2.getAndIncrement()) 
                System.out.print(i2 + " ");
            
        );
        thread2.start();
    


结果:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 16 1 2 17 18 3 4 19 20 5 6 7 8
9 10 11 12 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 13 37 38 39 
14 15 16 17 18 19 40 20 41 21 22 23 24 25 26 27 28 29 42 30 31 43 44 45 
46 47 48 32 33 34 49 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 

可以看到,这里会输出两次0-50的乱序数组,是可行的。

因此,可以得出结论: 如果我们想在多线程环境中,调用并修改成员变量,需要把成员变量复制多份,更改为static类型,或AtoimcInteger类型, 调用即可。

三. 多线程中修改调用局部变量


由于每个局部变量对于每个线程来说,都是私有的,因此直接调用修改即可,并不会影响到其他线程。 代码如下:

public class test 
    public static void main(String[] args) throws Exception 
        Thread thread1 = new Thread(() -> 
            int i = 0;
            for (i = 0; i < 50; i++) 
                System.out.println(i + " ");
            
        );
        thread1.start();

        Thread thread2 = new Thread(() -> 
            int i = 0;
            for (i = 0; i < 50; i++) 
                System.out.println(i + " ");
            
        );
        thread2.start();
    


输出:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 0 1 2 3 4 5 
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 
31 32 33 34 35 36 37 38 39 40 41 42 43 23 44 24 25 45 46 47 26 48 49 27 
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 

可以看到,这里会输出两次0-50的乱序数组,是可行的。

以上是关于别翻了,成员变量和局部变量在多线程中的使用,看这篇就够了的主要内容,如果未能解决你的问题,请参考以下文章

别翻了,成员变量和局部变量在多线程中的使用,看这篇就够了

别翻了,成员变量和局部变量在多线程中的使用,看这篇就够了

别翻了,Lambda 表达式入门,看这篇就够了

别翻了,这篇文章就是要让你入门java多线程!

java 局部静态变量在多线程环境下是不是有线程安全问题??

C++11:在多线程程序中使用局部静态变量导致 coredump