线程安全

如何实现线程安全?

谁说我不能喝 提交于 2020-01-26 15:08:00
文章目录 避免共享 不可变 可重入代码 线程封闭 必须共享 互斥同步 非阻塞同步 什么是线程安全?下面是我摘自java并发编程书里给的解释: 当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。 这个解释听的是不是云里雾里?我们说的通俗一点: 线程安全就是多线程并发访问的时候,线程之间所共享的资源不会被污染或被破坏。 我们知道线程共享的内存区域主要就是java堆,而java堆主要存的就是对象和数组,所有的全局变量都存储在堆中。也就是说我们想保证线程安全,就需要保证全局变量和堆内的对象不会受其他线程影响。 由此,我们可以从数据共享和不共享两个方面来讨论实现线程安全的方式。 避免共享 通过避免共享,让所有资源都编程线程私有,达到线程安全。主要实现方法有三种: 不可变 可重入代码 线程封闭 不可变 使用final类型 通过使用final类型修饰,发布不可变对象。 String属于不可变对象,可直接使用。 使用volatile类型 通过使用Volatile类型修饰,发布不可变对象。 volatile类型修饰的变量只适用于读多写少的情况,只能确保其可见性。如果要保证线程安全,则需要保证只有单个线程去修改。 可重入代码 若一个程序或子程序可以安全的被并行执行,则称其为可重入(reentrant),即允许多个进程同时访问。 可重入代码

Spring框架学习笔记-ThreadLocal基础知识

守給你的承諾、 提交于 2020-01-26 07:33:25
在前面我们已经说过,Spring通过各种模板降低了开发者使用各种数据持久化技术的难度。这些模板类都是线程安全的,也就是说,多个DAO可以复用同一个模板实例而不会发生冲突。 我们使用模板类访问底层数据,根据持久化技术的不同,模板类需要绑定数据连接或会话的资源。但这些资源本身是非线性安全的,也就是说它们不能在同一时刻被多个线程共享,虽然模板类通过资源池获取数据连接或对话,但资源池本身解决的是数据连接或对话的缓存问题,并非数据连接或对话的线程安全问题。 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用线程同步。但模板类并未采用线程同步机制,因为线程同步会降低并发性,影响系统性能。 那么模板类是靠的什么,可以在无需线程同步的情况下就化解了线程安全的难题呢?答案就是ThreadLocal! ThreadLocal在Spring里发挥着重要的作用,在管理request作用域的Bean、事务管理以及任务调度、AOP等模块都出现了它们的身影,起着举足轻重的作用。要想了解Spring事务管理的底层技术,ThreadLocal是必须攻克的山头堡垒。 1.ThreadLocal是什么 ThreadLocal是服务于Thread的一种 本地私有数据机制 ,threadlocalvariable(线程局部变量), 即为每一个使用该变量的线程都提供一个变量值的副本

面试-Java集合类

こ雲淡風輕ζ 提交于 2020-01-26 07:27:05
1.Java 容器分为 Collection 和 Map 两大类 Collection List(有顺序的collection,并且可以重复) ArrayList , LinkedList, Vector , Stack Set(不包含重复元素的collection) HashSet,LinkedHashSet,TreeSet Map(一组键和值映射的组合,键不能重复) · HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap,Hashtable 2.ArrayList与 LinkedList 1) ArrayList是基于动态数组的数据结构,内存存放地址连续,查询效率比较高,但插入和删除效率比较低。 2) LinkedList是基于链表的数据结构,不需开辟连续的内存空间,插入和删除操作效率比较高,但是查询效率比较低。 适用场景 : 当需要对数据进行多次访问则选择ArrayList,如果需要对数据进行多次增删改选择LinkedList。 3. ArrayList与 Vector 1) vector方法都是同步,线程安全,而ArrayList不是,因此性能比较好。 2) verctor当元素超过初始化的大小时,会自动将容量翻倍,而ArrayList只能50%,更有利于节约空间。 3) vector可设置增长因子。 适用场景 :

Java之ThreadLocal原理分析

独自空忆成欢 提交于 2020-01-25 16:58:24
简介 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。引自@ 枫之逆 人们常说,锁是一种以时间换空间的机制,而ThreadLocal正好是以空间换时间的。 和锁的比较 为什么要先强调这一点,因为从简介上看,容易使人们联想到ThreadLocal似乎是一种解决Java多线程环境中线程同步与线程安全方法,其实不然,这里要设计到两个概念:线程安全,线程同步,事实上,ThreadLocal只解决线程安全的问题,并不能解决线程同步的问题,这也造成在刚学习的时候,我总是在苦想,ThreadLocal既然为每个线程拷贝一份变量,那怎么再进行同步呢?查了很多资料后才想明白,ThreadLocal并不是用来解决线程同步的,所以它与锁可以说是没有什么关系的,彼此各有所长,不能代替

并发编程系列之八线程安全List list = new ArrayList()不是线程安全的

断了今生、忘了曾经 提交于 2020-01-25 15:21:06
并发编程系列之八线程安全List list = new ArrayList()不是线程安全的,ArrayList里面增删改查的操作,底层是数组的实现,效率很高但是线程不安全,在银行或者记账的场景中需要谨慎的使用这个集合类。 示例1.ConcurrentModificationException() removeIf boolean add(E e); boolean remove(Object o); 线程是不安全的,多线程下面没有使用synchronized或者lock关键字修饰,所以在多线程下面做添加或者删除操作很容易出现ConcurrentModificationException异常。这个即时多线程条件下面出现的一个异常。面试时候也会经常的提到ConcurrentModificationException这个异常会出现在哪里?我开发三年了,今年才突然醒悟这个出现在这里。下面源码里面可以查找一下没有使用任何的原子类,所以说这个类不是线程安全的。 package java.util; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; import sun.misc.SharedSecrets; /**

秒杀多线程系列中的题目

只愿长相守 提交于 2020-01-25 07:51:36
1. 什么是线程安全?(2012年5月百度实习生面试)   如果多线程的程序运行结果是可预期的,而且与单线程的程序运行结果一样,那么说明是“线程安全”的。 a. 线程的概念、线程的基本状态及状态之间的关系     另外, 这个网址 里面讲操作系统的知识倒是挺详实的,还有另外一种解释 线程概念   b.多线程的几种实现方法分别是什么?     这个貌似在java面试中会出现,我是专注于c++的,无视掉,但是不得不说, 秒杀多线程面试题系列 真心是个好总结   c.多线程同步与互斥有几种实现方法?都是什么?(C++)    临界区(CS:critical section)、事件(Event)、互斥量(Mutex)、信号量(semaphores),需要注意的是,临界区是效率最高的,因为基本不需要其    他的开销,二内核对象涉及到用户态和内核态的切换,开销较大,另外,关键段、互斥量具有 线程所有权 的概念,因此只可以用于线程之间互斥,而不能用到    同步中。只有互斥量能完美解决进程意外终止所造成的“遗弃问题”。   d.多线程同步和互斥有何异同,在什么情况下分别使用他们?举例说明    所谓同步,表示有先有后,比较正式的解释是“线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个    线程的消息时应等待,直到消息到达时才被唤醒。”所谓互斥

java 线程安全 Lock

那年仲夏 提交于 2020-01-25 07:20:49
 java.util.concurrent.locks   对于线程安全我们前面使用了synchronized关键字,对于线程的协作我们使用Object.wait()和Object.notify()。在JDK1.5中java为我们提供了Lock来实现与它们相同的功能,并且性能优于它们,在JDK1.6时,JDK对synchronized做了优化,在性能上两种方式差距不大了。 一、为什么出现lock   synchronized修饰的代码块,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,如果没有释放则需要无限的等待下去。获取锁的线程释放锁只会有两种情况:   1、获取锁的线程执行完了该代码块,然后线程释放对锁的占有。   2、线程执行发生异常,此时JVM会让线程自动释放锁。 Lock与synchronized对比:   1、Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问。   2、synchronized不需要手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。 二、java.util

单例模式——《设计模式》

橙三吉。 提交于 2020-01-25 04:01:31
概念 什么是单例模式? 首先,单例模式,属于 创建型 设计模式。 许多时候系统只需要拥有一个全局类,这样为了协调系统整体的行为。也就是说单例对象的类只能允许一个实例存在。 单例模式的优缺点 优点 在内存中只有一个对象,节省内存空间; 避免频繁的创建销毁对象,可以提高性能; 避免对共享资源的多重占用,简化访问; 为整个系统提供一个全局访问点。 缺点 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出; 如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失; 单例模式的实现 这里主要介绍两种:饿汉式单例、懒汉式单例 一、饿汉式单例 //饿汉式单例类.在类初始化时,已经自行实例化 public class Singleton1 { private Singleton1 ( ) { } private static final Singleton1 single = new Singleton1 ( ) ; //静态工厂方法 public static Singleton1 getInstance ( ) { return single ; } } 饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是 线程安全 的。 二、懒汉式单例 /

Java并发之线程安全

こ雲淡風輕ζ 提交于 2020-01-24 19:39:36
多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为。 线程安全的几种实现方式: 1.不可变 2.互斥同步 3.非阻塞同步 4.无同步方案 1.不可变 不可变(Immutable)的对象一定是线程安全的,不需要再采取任何的线程安全保障措施。只要一个不可变的对象被正确地构建出来,永远也不会看到它在多个线程之中处于不一致的状态。多线程环境下,应当尽量使对象成为不可变,来满足线程安全。 不可变的类型: final 关键字修饰的基本数据类型 String 枚举类型 Number 部分子类,如 Long 和 Double 等数值包装类型,BigInteger 和 BigDecimal 等大数据类型。但同为 Number 的原子类 AtomicInteger 和 AtomicLong 则是可变的。 对于集合类型,可以使用 Collections.unmodifiableXXX() 方法来获取一个不可变的集合。 2.互斥同步 互斥同步属于一种悲观的并发策略,总是认为只要不去做正确的同步措施,那就肯定会出现问题。无论共享数据是否真的会出现竞争,它都要进行加锁(这里讨论的是概念模型,实际上虚拟机会优化掉很大一部分不必要的加锁)、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。 使用synchronized 和 ReentrantLock。 3