线程安全

线程安全—可见性和有序性

馋奶兔 提交于 2019-12-21 18:57:04
在并发编程中,需要处理的两个关键问题: 线程之间如何通信 以及 线程之间如何同步 。 通信 是指线程之间以或者机制交换信息,java的并发采用的是共享内存模型,线程之间共享程序的公共状态,通过读写内存中的公共状态进行隐式通信。 同步 是是指程序中用于控制不同线程间操作发生相对顺序的机制。 最开始首先应该知道计算机中的 缓存 在其中起的作用 CPU Cache(高速缓存):由于计算机的存储设备与处理器的处理设备有着几个数量级的差距,所以现代计 算机都会加入一层读写速度与处理器处理速度接近相同的高级缓存来作为内存与处理器之间的缓冲,将运 算使用到的数据复制到缓存中,让运算能够快速的执行,当运算结束后,再从缓存同步到内存之中,这 样,CPU就不需要等待缓慢的内存读写了。 主(内)存:一个计算机包含一个主存,所有的CPU都可以访问主 存,主存比缓存容量大的多(CPU访问缓存层的速度快于访问主存的速度!但通常比访问内存寄存器的速度还是要慢点) 运作原理:通常情况下,当一个CPU要读取主存(RAM - Main Mernory)的时候,他会将主存中的数据读 取到CPU缓存中,甚至将缓存内容读到内部寄存器里面,然后再寄存器执行操作,当运行结束后,会 将寄存器中的值刷新回缓存中,并在某个时间点将值刷新回主存。 为什么需要CPU Cache? 答:CPU 的频率太快了,快到主存跟不上

设计模式-单例模式

百般思念 提交于 2019-12-21 17:23:43
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 单例模式有两种写法: 1: 饿汉模式 优点:饿汉模式天生是线程安全的,使用时没有延迟 缺点:启动时即创建实例,启动慢,有可能造成资源浪费 @Slf4j public class HungrySingle { private static HungrySingle hungrySingle = new HungrySingle(); public static HungrySingle getHungrySingle(){ log.info("HungrySingle::getHungrySingle::time:{}",(new Date()).getTime()); return hungrySingle; } } 2: 懒汉模式 优点:懒加载启动快,资源占用小,使用时才实例化,无锁 缺点:非线程安全 @Slf4j public class LazySingle { private static LazySingle lazySingle = null; public LazySingle() { } public static LazySingle getLazySingle(){ if(lazySingle == null){ lazySingle = new LazySingle(); } return

单例模式有几种写法?

六眼飞鱼酱① 提交于 2019-12-21 05:06:12
单例模式有几种写法? 前言 纠结单例模式有几种写法有用吗?有点用,面试中经常选择其中一种或几种写法作为话头,考查设计模式和coding style的同时,还很容易扩展到其他问题。 这里讲解几种笔者常用的写法,但切忌生搬硬套,去记“茴香豆的写法”。编程最大的乐趣在于“know everything, control everything”。 JDK版本:oracle java 1.8 大体可分为4类,下面分别介绍他们的基本形式、变种及特点。 饱汉模式 饱汉是变种最多的单例模式。 基础的饱汉 饱汉,即已经吃饱,不着急再吃,饿的时候再吃。所以他就先不初始化单例,等第一次使用的时候再初始化,即“懒加载”。 // 饱汉 // UnThreadSafe public class Singleton1 { private static Singleton1 singleton = null; private Singleton1() { } public static Singleton1 getInstance() { if (singleton == null) { singleton = new Singleton1(); } return singleton; } } 饱汉模式的核心就是懒加载。好处是更启动速度快、节省资源,一直到实例被第一次访问,才需要初始化单例;小坏处是写起来麻烦

线程 Z

为君一笑 提交于 2019-12-21 05:03:14
原文: http://www.albahari.com/threading/part5.aspx 专题: C#中的多线程 1并行编程 Permalink 在这一部分,我们讨论 Framework 4.0 加入的多线程 API,它们可以充分利用多核处理器。 并行 LINQ(Parallel LINQ)或称为 PLINQ Parallel 类 任务并行(task parallelism) 构造 SpinLock 和 SpinWait 这些 API 可以统称为 PFX(Parallel Framework,并行框架)。 Parallel 类与 任务并行构造 一起被称为 TPL(Task Parallel Library,任务并行库)。 Framework 4.0 也增加了一些更底层的线程构造,它们针对传统的多线程。我们之前讲过的: 低延迟信号构造 ( SemaphoreSlim 、 ManualResetEventSlim 、 CountdownEvent 以及 Barrier ) 取消标记(cancellation token) ,以便于协作取消 延迟初始化 ThreadLocal<T> 在继续阅读前,你需要了解第 1 部分 - 第 4 部分中的基本原理,特别是 锁 和 线程安全 。 并行编程这一部分提供的所有代码都可以在 LINQPad 中试验。LINQPad 是一个 C#

高效Java编码

别等时光非礼了梦想. 提交于 2019-12-21 05:02:24
1、常量 & 变量 Java 中存在两种类型的变量,基本类型+引用类型 1.1 直接赋值常量值,禁止声明新对象 1.2.当成员变量值无需改变时,尽量定义为静态常量 1.3.尽量使用基本数据类型,装箱 VS 拆箱 1.4.如果变量的初值会被覆盖,就没有必要给变量赋初值 1.5.尽量使用函数内的基本类型临时变量 在函数内,基本类型的参数和临时变量都保存在栈(Stack)中,访问速度较快;对象类型的参数和临时变量的引用都保存在栈(Stack)中,内容都保存在堆(Heap)中,访问速度较慢。在类中,任何类型的成员变量都保存在堆(Heap)中,访问速度较慢。 1.6.尽量不要在循环体外定义变量 在老版JDK中,建议“尽量不要在循环体内定义变量”,但是在新版的JDK中已经做了优化。通过对编译后的字节码分析,变量定义在循环体外和循环体内没有本质的区别,运行效率基本上是一样的。反而,根据“ 局部变量作用域最小化 ”原则,变量定义在循环体内更科学更便于维护,避免了延长大对象生命周期导致延缓回收问题 。 1.7.不可变的静态常量,尽量使用非线程安全类 1.8.不可变的成员变量,尽量使用非线程安全类 2、对象 & 类 2.1 禁止使用JSON转化对象 JSON提供把对象转化为JSON字符串、把JSON字符串转为对象的功能,于是被某些人用来转化对象。这种对象转化方式,虽然在功能上没有问题

史上最全Java集合面试题

╄→尐↘猪︶ㄣ 提交于 2019-12-20 22:37:30
1、你所知道的集合类都有哪些?主要方法? 最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变 大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索 引访问元素的情形。 Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作"键"和"值"), 其中每个键映射到一个值。 ArrayList/Vector List Collection HashSet/TreeSet Set HashTable Treemap/HashMap 我记的不是方法名,而是思想,我知道它们都有增删改查的方法,但这些方法的具体名称, 我记得不是很清楚,对于 set,大概的方法是 add,remove, contains;对于 map,大概的方 法就是 put,remove,contains 等,因为,我只要在 eclispe 下按点操作符,很自然的这些方 法就出来了。我记住的一些思想就是 List 类会有 get(int index)这样的方法,因为它可以按 顺序取元素,而 set 类中没有 get(int index)这样的方法。List 和 set 都可以迭代出所有元素, 迭代时先要得到一个 iterator 对象,所以,set 和 list 类都有一个 iterator 方法,用于返回那

Java容器总结

怎甘沉沦 提交于 2019-12-20 15:47:52
List ArrayList 底层为动态数组,因为它的增加、删除元素与size的变化不是原子操作,所以不是线程安全的 LinkedList 底层为双向链表,实现了List接口和Deque接口。不是线程安全的 Vector 创建了一个向量类的对象后,可以往其中随意插入不同类的对象。线程安全的,synchronized。替代方案:Collections.synchronizedList() Map HashMap 底层为哈希表,扩容时机和方式参考哈希表,不是线程安全。 JDK1.8中实现为哈希表+红黑树 LinkedHashMap 底层为哈希表和双向链表,保留元素的插入顺序,不是线程安全 TreeMap 红黑树,有序,非线程安全 Set HashSet 底层为HashMap,不是线程安全 LinkedHashSet 底层为哈希表和双向链表,不是线程安全 TreeSet 基于TreeMap,不是线程安全 EnumSet 是一个抽象类,非线程安全 HashTable 不允许空键或值,线程安全,synchronized,遗留类,不应该使用 ConcurrentHashMap HashTable的替代品,synchronized 来源: CSDN 作者: NeverWA 链接: https://blog.csdn.net/NeverWA/article/details/103627336

HashMap知识总结

不羁的心 提交于 2019-12-20 10:23:45
常见的数据结构 数组:长度固定,可以使用下标索引,所有元素类型一致。 列表:长度可变,可以包含重复的元素。 集合:长度可变,不能放置重复的元素。 堆栈:只允许对最后插入的元素进行操作。后进先出,通过仅有的peek(),push(),和pop()几个方法的强制性限制达到。 队列:先进先出,通过只提供peek(),offer()和poll()这几个方法来访问数据进行限制来达到的。 链表:链表是一种由多个节点组成的数据结构,每个节点包含有数据以及指向下一个节点的引用,在双向链表里还会有一个指向前一个节点的引用。 或许,可以用一张图直观的展现集合这个大家庭。 HashMap底层实现 由上图可知,HashMap实现了Map接口。其底层数据结构是哈希表,而hash表其实就是链表+数组(+红黑树 jdk8之后加入)。表现形式大致如下图: 初始化的表长度为什么是16: 之所以初始长度为16,目的是为了让hash既有数组快速查询优点,又能融合链表方便快捷增加删除元素的优势。 哈希表使用数组+链表的缺点:(两个极端) 1.每次计算hash值都是同一个值,如果每次计算的hash值都是同一个,会造成链表中长度过长的问题。 2.每次计算hash值都是不同的值,如果每次计算的hash值都不一样,会造成HashMap中数据不断扩容,造成容量不断增大。 为了解决这些问题,jdk1.8中使用红黑树代替了链表。

JAVA设计模式之单例模式

吃可爱长大的小学妹 提交于 2019-12-19 16:17:18
文章目录 1 懒汉式单例 1.1 在getInstance方法上加同步 1.2 双重检查锁定 1.3 静态内部类 2 饿汉式单例 3 登记式单例(可忽略) 4 饿汉式和懒汉式区别 从名字上来说,饿汉和懒汉: 另外从以下两点再区分以下这两种方式: 懒汉式中的1.1,1.2,1.3实现有什么区别: 什么是线程安全? 5 应用 转自: https://blog.csdn.net/jason0539/article/details/23297037/ 概念 :java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种: 懒汉式单例 、 饿汉式单例 、 登记式单例 。 单例模式有以下特点: 单例类只能有一个实例。 单例类必须自己创建自己的唯一实例。 单例类必须给所有其他对象提供这一实例。 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之, 选择单例模式就是为了避免不一致状态,避免政出多头。 1 懒汉式单例

线程安全之CAS机制详解(分析详细,通俗易懂)

筅森魡賤 提交于 2019-12-19 14:46:03
背景介绍: 假设现在有一个线程共享的变量c=0,让两个线程分别对c进行c++操作100次,那么我们最后得到的结果是200吗? 1.在线程不安全的方式下: 结果可能小于200,比如当前线程A取得c的值为3,然后线程A阻塞了,线程B取得的c的值也是3,然后线程B也阻塞了,现在线程A被唤醒执行了++操作使得c=4,结果写回c值内存,线程A执行结束,线程B被唤醒执行了++操作使得3++=4,也写回了c值内存,现在问题来了,两个线程分别进行了一次++操作,最后c值却为4而不是5,所以c值最后的结果肯定是小于200的,产生这种情况的原因就是线程不安全!,两个线程在同一时间读取了c值,然后又没有各种先执行完++操作而被阻塞(就是没有同步) 2.在线程安全的方式下: 比如++操作加上synchronized同步锁,结果一定是200,因为这样使得读取c值和++操作是一个原子性操作,不能被打断,所以线程是安全的,保证了同步 现在问题来了,我们要保证线程安全只有加synchorized同步锁这一种办法吗?synchorized同步锁又有什么缺点呢? 当然不仅只有synchorized这一种方法,还有原子操作类,关于原子操作类我们等下再说,先说说synchorized的缺点: syschorized缺点: synchorized的缺点关键在于性能!