天天看点

java多线程(线程共享)

java实现线程共享通过2种方式:静态变量、实例化变量

【理解概念】

静态变量:静态变量即类变量,位于方法区,为所有该类下的对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全。

实例变量: 实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程非安全;如果每个线程执行都是在不同的对象中,那对象与对象之间的实例变量的修改将互不影响,故线程安全。

【2者的区别】

存放位置

  • 类变量随着类的加载而存在于方法区中。
  • 实例变量随着对象的建立而存在于堆内存中。

生命周期

  • 类变量生命周期最长,随着类的消失而消失。
  • 实例变量生命周期随着对象的消失而消失。

类变量和实例变量的区别在于:类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象。

例子:

public class BB {
    public static int as = 0; // 静态变量
    public int ac = 0; // 实例变量
}


public class TT {

    public static void main(String[] args) throws Exception{
        BB bb1 = new BB();
        BB bb2 = new BB();

        // 设置 bb1 的静态变量为 3
        bb1.as = 3;
        // 设置 bb1 的实例变量为 4
        bb1.ac = 4;

        System.out.println("bb2获取的as值为:"+bb2.as);
        System.out.println("bb2获取的ac值为:"+bb2.ac);
    }
}           
bb2获取的as值为:3
bb2获取的ac值为:0           
  • 静态变量是针对所有对象的,所以bb1改变as, bb2的as也改变。
  • 实例只改变自身的,所以bb1对象的ac改变,不影响对象bb2的ac变量。

测试例子,卖票,注意都是线程不安全的

【静态变量测试】static int ticket = 10;

public class TestThread extends Thread {

    static int ticket = 10;

    @Override
    public void run() {
        while (ticket > 0){
            System.out.println(Thread.currentThread().getName() + " 卖票:"+ticket);
            ticket -- ;
        }
    }
}

public static void main(String[] args) throws Exception{
        for (int i = 0; i < 2; i++) {
            TestThread testThread = new TestThread();
            testThread.start();
        }
    }           
Thread-1 卖票:10
Thread-0 卖票:10
Thread-0 卖票:8
Thread-0 卖票:7
Thread-0 卖票:6
Thread-0 卖票:5
Thread-0 卖票:4
Thread-0 卖票:3
Thread-0 卖票:2
Thread-1 卖票:9
Thread-0 卖票:1           

【实例化变量】

public class TestThread implements Runnable {

    int ticket = 10;

    @Override
    public void run() {
        while (ticket > 0){
            System.out.println(Thread.currentThread().getName() + " 卖票:"+ticket);
            ticket -- ;
        }
    }
}

public static void main(String[] args) throws Exception{
       TestThread testThread = new TestThread();
        for (int i = 0; i < 2; i++) {
            new Thread(testThread).start();
        }
    }           
Thread-0 卖票:10
Thread-0 卖票:9
Thread-0 卖票:8
Thread-0 卖票:7
Thread-0 卖票:6
Thread-0 卖票:5
Thread-0 卖票:4
Thread-0 卖票:3
Thread-0 卖票:2
Thread-0 卖票:1
Thread-1 卖票:10           

如上代码中,虽然TestThread类中的ticket是普通成员变量,但同一个TestThread实例可以在多个线程对象间共享,如上main函数中,虽然创建了2个线程对象,但它们的target都是同一个TestThread对象,所以2个线程操作的ticket都是同一个实例的变量,从而达到信息共享的效果。