之前都是业务层次开发,现在公司进行的网络编程,一下子要了解太多java底层的东西并进行应用,我现在边学习边应用。由于知识能力有限,在上次发博客时出现了一个小小的纰漏,而这个纰漏被细心的博友发现了。

首先感谢你的关注,其次非常感谢你的建议和批评。其实上次博客中说道要线程安全的取得缓冲变量确实有安全取得某变量的意思,不过那个例子只是一个讲解Socket应用的小示例。如果真的要保证变量安全,使用静态变量,这好像有点不正常了。

其实这一下子就围绕在了一个话题上面,那就是变量的线程安全性。现在就一个个来说。

首先要肯定的是除了ThreadLocal和局部变量安全以外,静态和实例变量都是不安全的。

首先来看静态变量:

  1. package com;
  2. /**
  3. * @说明 变量安全测试
  4. * @author 崔素强
  5. */
  6. public class ThreadLocalTest {
  7. public static void main(String[] args) {
  8. Runnable accumelatora = new Accumulatort();
  9. Thread threada = new Thread(accumelatora, "ThreadA");
  10. Thread threadb = new Thread(accumelatora, "ThreadB");
  11. threada.start();
  12. threadb.start();
  13. }
  14. }
  15. class Accumulatort implements Runnable {
  16. // 静态变量
  17. private static int local = 0;
  18. @SuppressWarnings("unchecked")
  19. public void run() {
  20. // 静态变量
  21. for (int i = 0; i <= 10; i++) {
  22. local += 1;
  23. try {
  24. Thread.sleep(500);
  25. } catch (Exception e) {
  26. }
  27. System.out.println(Thread.currentThread().getName() + "-->"
  28. + local);
  29. }
  30. }
  31. }

运行后看控制台输出,很容就发现有时候某线程使用变量时已经被另一个线程修改了。

因为静态变量是 静态存储方式,所谓静态存储方式是指在程序运行期间分配固定的存储空间的方式。也就是说不管多少线程,访问都是一个变量,安全问题显而易见。

再说说实例变量:

  1. package com;
  2. /**
  3. * @说明 变量安全测试
  4. * @author 崔素强
  5. */
  6. public class ThreadLocalTest {
  7. public static void main(String[] args) {
  8. Runnable accumelatora = new Accumulatort();
  9. Thread threada = new Thread(accumelatora, "ThreadA");
  10. Thread threadb = new Thread(accumelatora, "ThreadB");
  11. threada.start();
  12. threadb.start();
  13. }
  14. }
  15. class Accumulatort implements Runnable {
  16. // 实例变量
  17. int locals = 0;
  18. @SuppressWarnings("unchecked")
  19. public void run() {
  20. for (int i = 0; i <= 10; i++) {
  21. locals += 1;
  22. try {
  23. Thread.sleep(1000);
  24. } catch (Exception e) {
  25. }
  26. System.out.println(Thread.currentThread().getName() + "-->"
  27. + locals);
  28. }
  29. }
  30. }

也许你觉得这会安全,但是运行后安全问题你会马上发现。

实例变量为对象实例私有,在java虚拟机的堆中分配,如果在系统中只存在一个此对象的实例,在多线程环境下,就像静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程非安全;如果每个线程执行都是在不同的对象中,那对象与对象之间的实例变量的修改将互不影响,所以线程安全。 而上面我们虽然是两个线程,但是对象却是一个,所以不是你想想中的安全了。

局部变量:

  1. package com;
  2. /**
  3. * @说明 变量安全测试
  4. * @author 崔素强
  5. */
  6. public class ThreadLocalTest {
  7. public static void main(String[] args) {
  8. Runnable accumelatora = new Accumulatort();
  9. Thread threada = new Thread(accumelatora, "ThreadA");
  10. Thread threadb = new Thread(accumelatora, "ThreadB");
  11. threada.start();
  12. threadb.start();
  13. }
  14. }
  15. class Accumulatort implements Runnable {
  16. @SuppressWarnings("unchecked")
  17. public void run() {
  18. // 局部变量
  19. int locals = 0;
  20. for (int i = 0; i <= 5; i++) {
  21. locals += 1;
  22. try {
  23. Thread.sleep(1000);
  24. } catch (Exception e) {
  25. }
  26. System.out.println(Thread.currentThread().getName() + "-->"
  27. + locals);
  28. }
  29. }
  30. }

不行你就多运行几遍,没事的,线程安全。

每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,所以没有安全问题。

一般多线程编程时最会想到的是ThreadLocal:

ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。

该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。

  1. package com;
  2. /**
  3. * @说明 变量安全测试
  4. * @author 崔素强
  5. */
  6. public class ThreadLocalTest {
  7. // 线程安全变量
  8. @SuppressWarnings("unchecked")
  9. public static ThreadLocal threadLocal = new ThreadLocal();
  10. public static void main(String[] args) {
  11. Runnable accumelatora = new Accumulatort();
  12. Thread threada = new Thread(accumelatora, "ThreadA");
  13. Thread threadb = new Thread(accumelatora, "ThreadB");
  14. threada.start();
  15. threadb.start();
  16. }
  17. }
  18. class Accumulatort implements Runnable {
  19. @SuppressWarnings("unchecked")
  20. public void run() {
  21. // 测试线程安全
  22. ThreadLocal threadLocal = ThreadLocalTest.threadLocal;
  23. for (int i = 1; i <= 10; i++) {
  24. if (threadLocal.get() == null)
  25. threadLocal.set(new Integer(0));
  26. int x = ((Integer) threadLocal.get()).intValue();
  27. x += 1;
  28. threadLocal.set(new Integer(x));
  29. try {
  30. Thread.sleep(1000);
  31. } catch (InterruptedException e) {
  32. }
  33. System.out.println(Thread.currentThread().getName() + "-->"
  34. + ((Integer) threadLocal.get()).intValue());
  35. }
  36. }
  37. }

上面的代码其实每个线程都会有自己的变量副本,所以也不会有安全问题的。

至于它和synchronized的区别,虽然都是为了线程安全,但是却又本质的区别。

synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。synchronized是用来处理多线程环境下的数据同步,而ThreadLocal只是为了保存当前线程私有的某种状态。

ThreadLocal,静态变量,实例变量,局部变量的线程安全的更多相关文章

  1. Java父类与子类中静态代码块 实例代码块 静态变量 实例变量 构造函数执行顺序

    实例化子类时,父类与子类中的静态代码块.实例代码块.静态变量.实例变量.构造函数的执行顺序是怎样的? 代码执行的优先级为: firest:静态部分 second:实例化过程 详细顺序为: 1.父类静态 ...

  2. 3.ruby语法基础,全部变量,实例变量,类变量,局部变量的使用和注意的要点

    1.ruby的全局变量的概念和Java的全局变量的概念不同, ruby的全局变量是以$符号开头的,如果给全局变量的初始化值为nil会出现警告. 赋值给全局变量,这是ruby不推荐的,这样会使程序变得很 ...

  3. iOS中的成员变量,实例变量,属性变量

    在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyV ...

  4. java入门---变量类型&类变量&局部变量&实例变量&静态变量

        在Java语言中,所有的变量在使用前必须声明.声明变量的基本格式如下:     type identifier [ = value][, identifier [= value] ...] ; ...

  5. JAVA类与对象(六)------实例变量与类变量的区别,实例方法和类方法的区别

    实例变量 实例变量声明在一个类中,但在方法.构造方法和语句块之外: 当一个对象被实例化之后,每个实例变量的值就跟着确定: 实例变量在对象创建的时候创建,在对象被销毁的时候销毁: 实例变量的值应该至少被 ...

  6. JAVA类与对象---实例变量与类变量的区别,实例方法和类方法的区别

    实例变量 实例变量声明在一个类中,但在方法.构造方法和语句块之外: 当一个对象被实例化之后,每个实例变量的值就跟着确定: 实例变量在对象创建的时候创建,在对象被销毁的时候销毁: 实例变量的值应该至少被 ...

  7. JAVA中 成员变量和和实例变量区别

    java语言支持的变量类型 类变量:独立于方法之外的变量,用 static 修饰. 局部变量:类的方法中的变量. 实例变量(全局变量):独立于方法之外的变量,不过没有 static 修饰. publi ...

  8. python(四)类变量和实例变量

    转载自[1] 实际这是个实例变量是否指向类变量的问题. python的类变量和实例变量,顾名思义,类变量是指跟类的变量,而实例变量,指跟类的具体实例相关联的变量,具体体现为self.x 等.实际要注意 ...

  9. 变量、变量作用域、常量final、变量的命名规范

    变量 变量是什么:就是可以变化的量! Java是一种强类型语言,每个变量都必须声明其类型. Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域. 注意事项: 每个变量都有类型,类 ...

随机推荐

  1. ionic下拉多项选择

    1.npm install ion-multi-picker --save 2.引入 import { MultiPickerModule } from 'ion-multi-picker'; imp ...

  2. ubuntu14.04禁用USB外存储设备

    ubuntu 14.04中禁用usb外存储设备: 在网上找了很多方法,大概都是下面的命令,而实际测试的时候没有什么作用. gsettings set org.gnome.desktop.media-h ...

  3. BZOJ 3489: A simple rmq problem KDtree

    Code: #include<bits/stdc++.h> #define maxn 200000 #define inf 100000000 #define mid ((l+r)> ...

  4. Sort HDU5884(二分+多叉哈夫曼树)

    HDU5884 Sort 题意:有n个序列要进行归并,每次归并的代价是两个序列的长度的和,要求最终的代价不能超过规定的T,求在此前提下一次能同时进行归并的序列的个数k. 思路:还是太单纯,看完题目一直 ...

  5. 基本数据类型:布尔型(bool)和空值None

    一.布尔型(bool) 布尔类型很简单,就两个值 ,一个True(真),一个False(假), 主要用记逻辑判断: 一件事情成立就是True,不成立就是False,也可以将bool值归类为数字, 是因 ...

  6. 基于requests模块的cookie,session和线程池爬取

    目录 基于requests模块的cookie,session和线程池爬取 基于requests模块的cookie操作 基于requests模块的代理操作 基于multiprocessing.dummy ...

  7. Ac自动机基础题集合

    Ac_automaton的板子打熟以后发现碰到题不会做,而且还是比较纯的板子,只要改几处地方就可以,Ac_automation有许多优秀而fantasy的性质,下面粘几个题,来记录一下做题的心得. 1 ...

  8. BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机、树状数组)

    吐槽: 为啥很多人用AC自动机暴力跳都过了?复杂度真的对么? 做法一: AC自动机+树状数组 姓名的问题,中间加个特殊字符连起来即可. 肯定是对点名串建AC自动机(map存儿子),然后第一问就相当于问 ...

  9. 美团 CodeM 复赛」城市网络

    美团 CodeM 复赛」城市网络 内存限制:64 MiB时间限制:500 ms标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接的连通图),首都为 11 ...

  10. noip模拟赛 党

    分析:一道非常恶心的dp题.每个人要么选或不选,很像是0-1背包,可以套用背包问题的状态,但是因为题目要求3个值,所以可以再加一维表示3个答案. f[i][j][k][l][p][0/1/2]表示i个 ...