线程安全

14个Java并发容器,你用过几个?

假如想象 提交于 2019-11-28 16:04:58
作者: acupt 前言 不考虑多线程并发的情况下,容器类一般使用ArrayList、HashMap等线程不安全的类,效率更高。在并发场景下,常会用到ConcurrentHashMap、ArrayBlockingQueue等线程安全的容器类,虽然牺牲了一些效率,但却得到了安全。 上面提到的线程安全容器都在java.util.concurrent包下,这个包下并发容器不少,今天全部翻出来鼓捣一下。 仅做简单介绍,后续再分别深入探索。 并发容器介绍 ConcurrentHashMap:并发版HashMap CopyOnWriteArrayList:并发版ArrayList CopyOnWriteArraySet:并发Set ConcurrentLinkedQueue:并发队列(基于链表) ConcurrentLinkedDeque:并发队列(基于双向链表) ConcurrentSkipListMap:基于跳表的并发Map ConcurrentSkipListSet:基于跳表的并发Set ArrayBlockingQueue:阻塞队列(基于数组) LinkedBlockingQueue:阻塞队列(基于链表) LinkedBlockingDeque:阻塞队列(基于双向链表) PriorityBlockingQueue:线程安全的优先队列 SynchronousQueue:读写成对的队列

2019 Java面试题

Deadly 提交于 2019-11-28 14:51:21
小编这里可是有Java面试题参考答案的哟,需要各位小伙伴下来逐一学习! 一、开场白 简单的介绍一下自己的工作经历与职责,在校或者工作中主要的工作内容,主要负责的内容;(你的信息一清二白的写在简历上,能答出来的最好写在上面,模棱两可不是很清楚的最好不要写,否则会被问的很尴尬) 介绍下自己最满意的,有技术亮点的项目或平台,重点介绍下自己负责那部分的技术细节;(主要对自己做过的事情是否有清晰的描述) 二、Java基础 什么是字符串常量池? String为什么是不可变的? String s = new String("xyz");究竟产生了几个对象,从JVM角度谈谈? String拼接字符串效率低,你知道原因吗? 你真的了解String的常见API吗? Java中的subString()真的会引起内存泄露么? 浅析Java中的final关键字? 浅析Java中的static关键字? 你对Java中的volatile关键字了解多少? i++是线程安全的吗?如何解决线程安全性? 从字节码角度深度解析 i++ 和 ++i 线程安全性原理? 请谈谈什么是CAS? 从源码角度看看ArrayList的实现原理? 手写LinkedList的实现,彻底搞清楚什么是链表? Java中方法参数的传递规则? Java中throw和throws的区别是什么? 重载和重写的区别? 手写ArrayList的实现

Map集合类(二.其他map集合jdk1.8)

限于喜欢 提交于 2019-11-28 14:47:49
1.hashtable(线程安全) 1.存储数据为数组+链表 2.存储键值对或获取时通过hash值取模数组长度确定节点在数组中的下标位置   int hash = key.hashCode();   int index = (hash & 0x7FFFFFFF) % tab.length;   Entry<K,V> entry = (Entry<K,V>)tab[index]; 3.其如put\get及其他public方法均加上synchronized 关键字 4.所有线程对同一hashTable实例操作时,锁住对象,故访问同一HashTable实例的线程都必须竞争同一把锁,效率低下 2.concurrentHashMap(线程安全) 1.存储数据为数组+链表+红黑树与hashMap类似,下标也一样index = (n - 1) & hash 2.读操作是支持并发操作的。 3.对比hashMap操作数组链表树时使用使用了unSafe方法,通过直接操作内存的方式来保证并发处理的安全性,使用的是硬件的安全机制。 3.2.同步处理主要是通过Synchronized和unsafe(cas原子操作)两种方式来完成的 3.3.在取得sizeCtl、某个位置的Node的时候,使用的都是unsafe的方法,来达到并发安全的目的,当需要在某个位置设置节点的时候

挑战10个最难的Java面试题(附答案)【上】

怎甘沉沦 提交于 2019-11-28 14:32:55
这是收集的10个最棘手的Java面试问题列表。这些问题主要来自 Java 核心部分 ,不涉及 Java EE 相关问题。你可能知道这些棘手的 Java 问题的答案,或者觉得这些不足以挑战你的 Java 知识,但这些问题都是容易在各种 Java 面试中被问到的,而且包括我的朋友和同事在内的许多程序员都觉得很难回答。 1 为什么等待和通知是在 Object 类而不是 Thread 中声明的? 一个棘手的 Java 问题,如果 Java编程语言不是你设计的,你怎么能回答这个问题呢。Java编程的常识和深入了解有助于回答这种棘手的 Java 核心方面的面试问题。 为什么 wait,notify 和 notifyAll 是在 Object 类中定义的而不是在 Thread 类中定义 这是有名的 Java 面试问题,招2~4年经验的到高级 Java 开发人员面试都可能碰到。这个问题的好在它能反映了面试者对等待通知机制的了解, 以及他对此主题的理解是否明确。就像为什么 Java 中不支持多继承或者为什么 String 在 Java 中是 final 的问题一样,这个问题也可能有多个答案。 为什么在 Object 类中定义 wait 和 notify 方法,每个人都能说出一些理由。从我的面试经验来看, wait 和 nofity 仍然是大多数Java 程序员最困惑的,特别是2到3年的开发人员

乐观锁的一种实现方式——CAS

早过忘川 提交于 2019-11-28 14:19:16
在 深入理解乐观锁与悲观锁 一文中我们介绍过锁。本文在这篇文章的基础上,深入分析一下乐观锁的实现机制,介绍什么是CAS、CAS的应用以及CAS存在的问题等。 线程安全 众所周知,Java是多线程的。但是,Java对多线程的支持其实是一把双刃剑。一旦涉及到多个线程操作共享资源的情况时,处理不好就可能产生线程安全问题。线程安全性可能是非常复杂的,在没有充足的同步的情况下,多个线程中的操作执行顺序是不可预测的。 Java里面进行多线程通信的主要方式就是共享内存的方式,共享内存主要的关注点有两个:可见性和有序性。加上复合操作的原子性,我们可以认为Java的线程安全性问题主要关注点有3个:可见性、有序性和原子性。 Java内存模型 (JMM)解决了可见性和有序性的问题,而锁解决了原子性的问题。这里不再详细介绍JMM及锁的其他相关知识。但是我们要讨论一个问题,那就是锁到底是不是有利无弊的? 锁存在的问题 Java在JDK1.5之前都是靠 synchronized 关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程持有共享变量的锁,都采用独占的方式来访问这些变量。独占锁其实就是一种悲观锁,所以可以说 synchronized 是悲观锁。 悲观锁机制存在以下问题: 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。

单例模式

走远了吗. 提交于 2019-11-28 14:03:23
单例是java中常见的模式,大多数人对这个都有一定的了解。 单例模式具有以下特点 1.只有一个实例对象 2.这个对象由自身类创建 3.这个对象由自身类提供 单例写法有好多种,今天来说说饿汉模式和懒汉模式 一丶饿汉模式 //饿汉模式 class EagerSingleton { private EagerSingleton() {} private static EagerSingleton instance = new EagerSingleton(); public EagerSingleton getInstance(){ return instance; } } 饿汉模式的实例在类初始化的时候就创建完成所以天生就是线程安全 二丶懒汉模式 public class LazySingleton { private static LazySingleton instance = null; private LazySingleton(){}; //普通懒汉模式 public static LazySingleton getInstance(){ if(instance == null){ instance = new LazySingleton(); } return instance; } //线程安全 public static synchronized

JUC 一 CopyOnWriteArrayList 和 CopyOnWriteArraySet

£可爱£侵袭症+ 提交于 2019-11-28 13:56:53
CopyOnWriteArrayList 是一个线程安全的 ArrayList ,通过内部的 volatile数组 和 显式锁ReentrantLock 来实现线程安全。 CopyOnWriteArraySet 是线程安全的 Set ,它是由 CopyOnWriteArrayList 实现,内部持有一个 CopyOnWriteArrayList 引用,所有的操作都是由 CopyOnWriteArrayList 来实现的,区别就是 CopyOnWriteArraySet 是无序的,并且不允许存放重复值。 适用场景 适合元素比较少,并且读取操作高于更新(add/set/remove)操作的场景 由于每次更新需要复制内部数组,所以更新操作开销比较大 内部的迭代器 iterator 使用了“快照”技术,存储了内部数组快照, 所以它的 iterator 不支持remove、set、add操作,但是通过迭代器进行并发读取时效率很高。 源码 /** * The lock protecting all mutators. (We have a mild preference * for builtin monitors over ReentrantLock when either will do.) */ final transient Object lock = new Object(); /*

Java集合详解

会有一股神秘感。 提交于 2019-11-28 13:50:37
一、数组和集合的比较 数组不是面向对象的,存在明显的缺陷,集合弥补了数组的缺点,比数组更灵活更实用,而且不同的集合框架类可适用不同场合。如下: 1:数组能存放基本数据类型和对象,而集合类存放的都是对象的引用,而非对象本身! 2:数组容易固定无法动态改变,集合类容量动态改变。 3:数组无法判断其中实际存有多少元素,length只告诉了数组的容量,而集合的size()可以确切知道元素的个数 4:集合有多种实现方式和不同适用场合,不像数组仅采用顺序表方式 5:集合以类的形式存在,具有封装、继承、多态等类的特性,通过简单的方法和属性即可实现各种复杂操作,大大提高了软件的开发效率 二、Java集合 此图可用Windows系统自带画图工具查看比较清晰 Collection和Map,是集合框架的根接口。 Collection的子接口: Set:接口 ---实现类: HashSet、LinkedHashSet Set的子接口SortedSet接口---实现类:TreeSet List:接口---实现类: LinkedList,Vector,ArrayList List集合 有序列表,允许存放重复的元素; 实现类: ArrayList:数组实现,查询快,增删慢,轻量级;(线程不安全) LinkedList:双向链表实现,增删快,查询慢 (线程不安全) Vector:数组实现,重量级 (线程安全

几种线程相关的map介绍

落爺英雄遲暮 提交于 2019-11-28 13:34:41
Java中平时用的最多的Map集合就是HashMap了,它是线程不安全的。 看下面两个场景: 1、当用在方法内的局部变量时,局部变量属于当前线程级别的变量,其他线程访问不了,所以这时也不存在线程安全不安全的问题了。 2、当用在单例对象成员变量的时候呢?这时候多个线程过来访问的就是同一个HashMap了,对同个HashMap操作这时候就存在线程安全的问题了。 线程安全的Map 为了避免出现场景2的线程安全的问题,不能使用HashMap作为成员变量,要寻求使用线程安全的Map,下面来总结下有哪些线程安全的Map呢? 1、HashTable private Map<String, Object> map = new Hashtable<>(); 来看看HashTable的源码 HashTable的get/put方法都被synchronized关键字修饰,说明它们是方法级别阻塞的,它们占用共享资源锁,所以导致同时只能一个线程操作get或者put,而且get/put操作不能同时执行,所以这种同步的集合效率非常低,一般不建议使用这个集合。 2、SynchronizedMap private Map<String, Object> map = Collections.synchronizedMap(new HashMap<String, Object>());

HashMap、HashTable、ConcurrentHashMap区别

不问归期 提交于 2019-11-28 13:22:02
HashMap和HashTable有何不同? 线程安全: HashTable 中的方法是同步的,而HashMap中的方法在默认情况下是非同步的。在多线程并发的环境下,可以直接使用HashTable,但是要使用HashMap的话就要自己增加同步处理了。 继承关系: HashTable是基于陈旧的Dictionary类继承来的。 HashMap继承的抽象类AbstractMap实现了Map接口。 允不允许null值: HashTable中,key和value都不允许出现null值,否则会抛出NullPointerException异常。 HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。 默认初始容量和扩容机制: HashTable中的hash数组初始大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。原因参考全网把Map中的hash()分析的最透彻的文章,别无二家。-HollisChuang's Blog 哈希值的使用不同 : HashTable直接使用对象的hashCode。 HashMap重新计算hash值。 遍历方式的内部实现上不同 : Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。