Java-ThreadLoal案例以及分析

案例

	public class Demo_ThreadLocal {
    private ThreadLocal<Integer> count = new ThreadLocal<Integer>() {//注意这里一定要指定泛型类型,此语法是匿名子类
        @Override
        protected Integer initialValue() {
            return new Integer(0);
        }
    };

    public int getNext() {
        Integer value = count.get();
        value++;
        count.set(value);
        return value;
    }

    public static void main(String[] args) {
        Demo_ThreadLocal d = new Demo_ThreadLocal();
        /**
         * 线程1创建以及启动
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("我是线程1" + Thread.currentThread().getName() + " " + d.getNext());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        /**
         * 线程2创建以及启动
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("我是线程2" + Thread.currentThread().getName() + " " + d.getNext());
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        /**
         * 线程3创建以及启动
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("我是线程3" + Thread.currentThread().getName() + " " +
                            " " + d.getNext());
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

   	 }
	}

控制台的输出(由于每个线程的执行任务都是用while(true)来修饰的,所以只能也只需截取一部分):

我是线程1Thread-0 1
我是线程2Thread-1 1
我是线程3Thread-2 1
我是线程1Thread-0 2
我是线程2Thread-1 2
我是线程1Thread-0 3
我是线程1Thread-0 4
我是线程3Thread-2 2
我是线程2Thread-1 3
我是线程1Thread-0 5

分析:

  1. 将每个线程分别看,每个线程都最后的计数都是从0开始:0、1、2、3逐步递增的,由此可见对于不同线程而言,各线程对应的ThreadLocal对象调用出的值相互独立,都是互不影响地从0,1,2如此递增的;
  2. 三个不同线程的sleep的输入参数不一样,线程1(对应Thread-0)为1s,线程2为2s,线程为3s;因此三个线程对应的ThreadLocal类对象中的值虽然是在递增,但是速度不一样,最快的线程1已经为5,线程3才为2;

ThreadLocal类的注意事项

  1. ThreadLocal类并不是Thread类的一个实例对象,“线程的局部变量”功能的实现是根据不同的线程,返回不同的数据引用,且各个数据引用之间相互独立。
  2. 其能够实现“线程的局部变量”功能的原因是,调用ThreadLocal类对象是在线程的run方法中进行的,而得到相关值又是调用了以下所示的代码。
    public T get() { Thread t = Thread.currentThread();.......
  3. 从内存角度看,value值是属于ThreadLocal对象的,而不是属于Thread线程的。前者更像一个HashMap一样,key为Thread对象,value为线程局部变量,这一点是可以通过查看ThreadLocal的实现代码得到的。
  4. 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal类/synchronized关键字的对比:

  1. 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
  2. ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
  3. 创建一个threadLocal类的对象时,就需要确定其返回的泛型类型。并且在主线程(mian方法)中创建一个threadLocal类对象时,无需指定其将存储多少个Thread类对象所对应的值,因为其是自动扩容的(类似于StringBuilder)。
  4. 线程的run方法中调用ThreadLocal类对象所存的值直接使用“ThreadLocal类对象.get方法”,而无需入口参数处设置当前的线程ID或者名字。

变量的作用域角度辨别ThreadLoal、局部变量、全局变量

Java是一门面向对象的语言,所以变量要么存在于类中,要么存在于方法中。

  1. 全局变量的作用域:存在于类中的变量,都被称作去全局变量。其又可以分为静态变量,可以被所有类所定义的实例对象访问,也可以直接类名.变量访问。非静态变量则属于类的实例,实例之间变量是相互独立的。
  2. 局部变量的作用域:方法以及代码块中所定义的变量都是局部变量,出了方法或者代码块,局部变量将无法被识别出来。
  3. ThreadLocal类实例中变量的作用域:假如是一个普通的Integer类型对象,其是同一个对象被多个线程访问。但是ThreadLocal类的作用域可以看作是一个线程一个作用域,线程中方法越多,ThreadLocal类在此线程中的作用域也就越广。通过ThreadLocal类内部Map结构的实现,变量的作用域做到了不再是对象,而是变得更窄,更特殊化的线程。

  所以,全局变量作用域是类或者对象,局部变量的作用域是方法,而ThreadLocal类中的变量以及引用变量的作用域则是某一个线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值