`
cuisuqiang
  • 浏览: 3958969 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
3feb66c0-2fb6-35ff-968a-5f5ec10ada43
Java研发技术指南
浏览量:3669028
社区版块
存档分类
最新评论

ThreadLocal,静态变量,实例变量,局部变量的线程安全,回复:ByteBuffer 到底怎么用?网络编程中一点总结!

    博客分类:
  • JDK
阅读更多

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

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

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

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

首先来看静态变量:

package com;
/**
 * @说明 变量安全测试
 * @author 崔素强
 */
public class ThreadLocalTest {
	
	public static void main(String[] args) {
		Runnable accumelatora = new Accumulatort();
		Thread threada = new Thread(accumelatora, "ThreadA");
		Thread threadb = new Thread(accumelatora, "ThreadB");
		threada.start();
		threadb.start();
	}
}
class Accumulatort implements Runnable {
	// 静态变量
	private static int local = 0;
	@SuppressWarnings("unchecked")
	public void run() {
		 // 静态变量
		for (int i = 0; i <= 10; i++) {
			local += 1;
			try {
				Thread.sleep(500);
			} catch (Exception e) {
			}
			System.out.println(Thread.currentThread().getName() + "-->"
					+ local);
		}
	}
}

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

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

再说说实例变量:

package com;
/**
 * @说明 变量安全测试
 * @author 崔素强
 */
public class ThreadLocalTest {
	public static void main(String[] args) {
		Runnable accumelatora = new Accumulatort();
		Thread threada = new Thread(accumelatora, "ThreadA");
		Thread threadb = new Thread(accumelatora, "ThreadB");
		threada.start();
		threadb.start();
	}
}
class Accumulatort implements Runnable {
	// 实例变量
	int locals = 0;
	@SuppressWarnings("unchecked")
	public void run() {
		for (int i = 0; i <= 10; i++) {
			locals += 1;
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
			System.out.println(Thread.currentThread().getName() + "-->"
					+ locals);
		}
	}
}

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

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

局部变量:

package com;
/**
 * @说明 变量安全测试
 * @author 崔素强
 */
public class ThreadLocalTest {
	public static void main(String[] args) {
		Runnable accumelatora = new Accumulatort();
		Thread threada = new Thread(accumelatora, "ThreadA");
		Thread threadb = new Thread(accumelatora, "ThreadB");
		threada.start();
		threadb.start();
	}
}
class Accumulatort implements Runnable {
	@SuppressWarnings("unchecked")
	public void run() {
		// 局部变量
		int locals = 0;
		for (int i = 0; i <= 5; i++) {
			locals += 1;
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
			System.out.println(Thread.currentThread().getName() + "-->"
					+ locals);
		}
	}
}

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

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

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

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

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

 

package com;
/**
 * @说明 变量安全测试
 * @author 崔素强
 */
public class ThreadLocalTest {
	// 线程安全变量
	@SuppressWarnings("unchecked")
	public static ThreadLocal threadLocal = new ThreadLocal();

	public static void main(String[] args) {
		Runnable accumelatora = new Accumulatort();
		Thread threada = new Thread(accumelatora, "ThreadA");
		Thread threadb = new Thread(accumelatora, "ThreadB");
		threada.start();
		threadb.start();
	}
}
class Accumulatort implements Runnable {
	@SuppressWarnings("unchecked")
	public void run() {
		// 测试线程安全
		ThreadLocal threadLocal = ThreadLocalTest.threadLocal;
		for (int i = 1; i <= 10; i++) {
			if (threadLocal.get() == null)
				threadLocal.set(new Integer(0));
			int x = ((Integer) threadLocal.get()).intValue();
			x += 1;
			threadLocal.set(new Integer(x));
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
			System.out.println(Thread.currentThread().getName() + "-->"
					+ ((Integer) threadLocal.get()).intValue());
		}
	}
}

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

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

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

 

请您到ITEYE看我的原创:http://cuisuqiang.iteye.com

或支持我的个人博客,地址:http://www.javacui.com

 

分享到:
评论
3 楼 haizhan 2013-11-05  
言简意赅呀 ,受用
2 楼 cuisuqiang 2012-08-03  
落花残月 写道
感觉最后用的ThreadLocal没有意义啊,都是局部变量...

用到的时候就有意义了!
1 楼 落花残月 2012-08-03  
感觉最后用的ThreadLocal没有意义啊,都是局部变量...

相关推荐

    局部变量线程安全测试

    在编程领域,线程安全是多线程编程中的一个重要概念,尤其在Java、C++等支持并发编程的语言中。线程安全通常指的是当多个线程访问一个对象时,如果对象的状态始终保持一致,那么我们就说这个对象是线程安全的。这里...

    ThreadLocal应用示例及理解

    **线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...

    简单分析Java线程编程中ThreadLocal类的使用共

    Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,而是一种能够确保每个线程都拥有独立副本的变量容器。理解ThreadLocal的工作...

    多线程线程变量赋值

    在编程领域,多线程是实现并发执行任务的重要机制,特别是在服务器端开发和高并发应用中。当多个线程共享同一资源时,数据同步和安全问题就会变得至关重要。本话题聚焦于“多线程线程变量赋值”,讨论如何在不通过...

    ThreadLocal 线程本地变量 及 源码分析.rar_开发_设计

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境下提供线程局部变量。它为每个线程创建了一个独立的变量副本,每个线程只能访问自己的副本,不会影响其他线程。这种机制有助于实现线程安全,尤其在需要线程...

    java ThreadLocal多线程专属的变量源码

    java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...

    ThreadLocal

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...

    java线程安全测试

    Java线程安全是多线程编程中的一个关键概念,它涉及到多个线程访问共享资源时可能出现的问题。在Java中,线程安全问题通常与并发、内存模型和可见性有关。Java内存模型(JMM)定义了如何在多线程环境下共享数据的...

    java中ThreadLocal类的使用

    线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面我们将深入探讨`ThreadLocal`的工作原理、使用场景以及常见误区。 `ThreadLocal`...

    Java中ThreadLocal的设计与使用

    Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,用于为每个线程提供独立的变量副本。理解ThreadLocal的工作原理和使用方法对于编写高效、安全的多线程程序至关重要。 ### ...

    ThreadLocal原理及在多层架构中的应用

    综上所述,ThreadLocal是Java多线程编程中的一个重要工具,合理使用能解决许多并发问题,但同时也需要注意其潜在的风险。在多层架构中,ThreadLocal可以有效地提高代码的可读性和性能,但也需要谨慎使用,遵循最佳...

    servlet与Struts action线程安全问题分析

    1. **避免使用实例变量**:尽可能使用局部变量,局部变量只存在于方法的执行上下文中,不会被多个线程共享,因此不存在线程安全问题。 2. **使用同步控制**:通过`synchronized`关键字对关键代码块或方法进行同步,...

    正确理解ThreadLocal.pdf

    `ThreadLocal`是一种强大的工具,它简化了多线程编程中对线程局部数据的管理,提高了代码的可读性和可维护性。然而,不当的使用也可能导致内存泄漏和其他潜在问题。因此,在使用`ThreadLocal`时,应当充分理解其工作...

    java线程安全总结.doc

    Java线程安全是多线程编程中的一个关键概念,它涉及到在并发环境下如何正确地管理共享资源,确保程序的正确性和一致性。以下是对Java线程安全的深入总结: ### 一、线程安全的定义 线程安全是指当多个线程访问同一...

    java中ThreadLocal详解

    在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,可能会引发线程安全问题。而`ThreadLocal`则提供了另一种...

    线程安全总结.doc

    线程安全是Java多线程编程中的一个重要概念,确保在多线程环境下程序能够正确地运行,避免数据错误和资源竞争等问题。本文档旨在从基础概念出发,详细介绍导致线程不安全的原因、如何避免线程不安全现象的发生,并...

    ThreadLocal 内存泄露的实例分析1

    `ThreadLocal` 是 Java 中用于在单个线程内存储线程局部变量的类,每个线程都有自己的副本,不会互相干扰。`MyThreadLocal` 是 `ThreadLocal` 的子类,用于存储 `MyCounter` 对象。在 `LeakingServlet` 的 `doGet` ...

    ThreadLocal简单Demo

    **线程局部变量(ThreadLocal)** 在Java编程中,`ThreadLocal`是...以上就是关于`ThreadLocal`及其内部类`ThreadLocalMap`的基础知识,它们在多线程编程中起到关键作用,帮助开发者实现高效、安全的线程局部变量管理。

Global site tag (gtag.js) - Google Analytics