Java 线程并发/ThreadLocal 用法举例

  1. 一个进程包含多个线程,这些线程共享堆空间,只有栈空间是每个线程独有的。
  2. 局部变量存放在栈空间,成员变量存放在堆空间。

由以上两点可以推出,线程并发时,如果同时操作了成员变量,会出问题。

public class ThreadTest {
    private String userName;

    public void test() {
        Thread t1 = new Thread() {
            public void run() {
                userName = "LiLei";
                process(this);
            }
        };
        Thread t2 = new Thread() {
            public void run() {
                userName = "HanMeiMei";
                process(this);
            }
        };
        t1.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
    }

    private void process(Thread t) {
        System.out.println(t + ": Hello, " + userName);
        try {
            t.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(t + ": Bye, " + userName);
    }

    public static void main(String[] args) {
        new ThreadTest().test();
    }
}

输出如下:

Thread[Thread-0,5,main]: Hello, LiLei
Thread[Thread-1,5,main]: Hello, HanMeiMei
Thread[Thread-0,5,main]: Bye, HanMeiMei
Thread[Thread-1,5,main]: Bye, HanMeiMei

第一个线程,进来的是 LiLei,出去的是 HanMeiMei……(大变活人?!)肯定是有问题的。

可以通过加同步锁来解决,也可以用 ThreadLocal,让每个线程拥有一份特定成员变量的拷贝。

public class ThreadLocalTest {
    private ThreadLocal<String> userNameThreadLocal = new ThreadLocal<>();

    public void test() {
        Thread t1 = new Thread() {
            public void run() {
                userNameThreadLocal.set("LiLei");
                process(this);
            }
        };
        Thread t2 = new Thread() {
            public void run() {
                userNameThreadLocal.set("HanMeiMei");
                process(this);
            }
        };

        t1.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
    }

    private void process(Thread t) {
        System.out.println(t + ": Hello, " + userNameThreadLocal.get());
        try {
            t.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(t + ": Bye, " + userNameThreadLocal.get());
    }

    public static void main(String[] args) {
        new ThreadLocalTest().test();
    }
}

输出如下:

Thread[Thread-0,5,main]: Hello, LiLei
Thread[Thread-1,5,main]: Hello, HanMeiMei
Thread[Thread-0,5,main]: Bye, LiLei
Thread[Thread-1,5,main]: Bye, HanMeiMei