synchronized

ConcurrentHashMap 原理解析(JDK1.8)

匿名 (未验证) 提交于 2019-12-02 23:35:02
了解ConcurrentHashMap 实现原理,建议首先了解下 HashMap 实现原理。 HashMap 源码解析(JDK1.8) 为什么要用ConcurrentHashMap HashMap线程不安全,而Hashtable是线程安全,但是它使用了synchronized进行方法同步,插入、读取数据都使用了synchronized,当插入数据的时候不能进行读取(相当于把整个Hashtable都锁住了,全表锁),当多线程并发的情况下,都要竞争同一把锁,导致效率极其低下。而在JDK1.5后为了改进Hashtable的痛点,ConcurrentHashMap应运而生。 ConcurrentHashMap为什么高效? JDK1.5中的实现 ConcurrentHashMap使用的是分段锁技术,将ConcurrentHashMap将锁一段一段的存储,然后给每一段数据配一把锁(segment),当一个线程占用一把锁(segment)访问其中一段数据的时候,其他段的数据也能被其它的线程访问,默认分配16个segment。默认比Hashtable效率提高16倍。 ConcurrentHashMap的结构图如下(网友贡献的图,哈): Paste_Image.png JDK1.8中的实现 ConcurrentHashMap取消了segment分段锁

synchronize - dz̸

匿名 (未验证) 提交于 2019-12-02 23:34:01
一、基本介绍: 关键字 ,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。 二、synchronized实现原理 在java代码中使用synchronized可是使用在代码块和方法中,根据Synchronized用的位置可以有这些使用场景: 还有比较详细的说明,请看文章: https://www.jianshu.com/p/d53bf830fa09 举个简单例子 package com.youyou.ch1.syn;public class SynClzAndInst { //使用类锁的线程 private static class SynClass extends Thread{ @Override public void run() { System.out.println("TestClass is running..."); synClass(); } } //使用对象锁的线程 private static class InstanceSyn

synchronized 锁优化

匿名 (未验证) 提交于 2019-12-02 23:32:01
jdk1.7之后,synchronized引入了 偏向锁,自旋锁,轻量级锁,重量级锁 自旋锁 当线程在获取锁的时候,如果发现锁已经由其他线程获得,这时候线程会先进行自旋,就是循环。如果在循环次数内这个线程得到了锁,那么他就进入。如果没有就转到轻量级锁 轻量级锁 代码进入同步块的时候,如果对象没有被锁定 虚拟机会在当前栈帧下创建一个lock record的锁记录空间,用来存储锁对象 markword的拷贝。然后虚拟机将使用cas操作将markword更新为指向lock record的指针,如果更新成功 那这个线程就拥有了锁。并更新锁对象的markword 为00 ,表示锁对象处于轻量级锁。 如果更新失败,就说明有其他线程竞争这个锁,如果有2条线程以上,轻量级锁就会升级为重量级锁。 在没有锁竞争的情况下 使用cas 操作,就避免互斥的开销 偏向锁 轻量级锁是在没有锁竞争的情况下,使用cas 操作 去除互斥的操作。那么偏向锁就是在没有锁竞争的情况下,连cas都不用了。 锁会偏向第一个获取它的那个线程。hotpost作者认为,在大多数情况下是没有锁竞争的,并且同一个线程 会重复获得这一把锁。添加偏向锁 就是为了让获得锁的代价更低 当一个线程获取到锁的时候,会使用cas操作,把当前线程的id记录到锁对象的markword中。 以后这个线程在进入和退出这个同步块的时候

Java面向对象程序设计第9章1-9

这一生的挚爱 提交于 2019-12-02 23:21:07
Java面向对象程序设计第9章1-9 1. 线程和进程的联系和区别是什么? 联系: 一个进程可以包括多个线程。 区别: 进程: 进程是一个具有一定 独立功能的程序 关于某个数据集合的一次运行活动,它是 系统 进行 资源分配和调度的一个独立单位 。 线程: 线程是进程的一个实体 ,是 CPU调度和分配的基本单位 。线程基本不拥有系统资源,与同一个进程的其他线程共享进程中所拥有的所有资源。 2. 什么是前台线程,什么是后台线程? 应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出, 所有的后台线程在应用程序退出时都会自动结束 。 3. 创建线程有几种方法?它们之间的区别是什么? 第一种方式 : 直接继承线程Thread类 创建对象 1.Thread子类无法再从其它类继承(java语言单继承)。 2.编写简单,run()方法的当前对象就是线程对象,可直接操作。 public MyThread extends Thread{ …… public void run() { 线程体逻辑 } } //创建及启动线程: MyThread t = new MyThread(); t.start(); 第二种方式:使用Runnable接口 创建线程 1.可以实现 多个线程资源共享 2.线程体run(

【多线程】Collections.synchronizedList生成线程安全的list的原理

匿名 (未验证) 提交于 2019-12-02 22:56:40
ArrayList 不是线程安全,可以通过Collections.synchronizedList生成线程安全的list Collections.synchronizedList(new ArrayList()) 该方法的本质是:在对原始arraylist操作时,都会增加关键字synchronized 保证线程安全(类似静态代理)。 public E get(int index) { public E set(int index, E element) { public void add(int index, E element) { public E remove(int index) { 文章来源: 【多线程】Collections.synchronizedList生成线程安全的list的原理

[Java并发编程实战]什么是锁顺序死锁

匿名 (未验证) 提交于 2019-12-02 21:53:52
精诚所至,金石为开。―――《后汉书・广陵思王荆传》 意思是人的诚心所到,能感动天地,使金石为之开裂。比喻只要专心诚意去做,什么疑难问题都能解决。 两个线程试图通过不同的顺序获取多个相同的锁。如果请求的顺序不相同,那么会出现循环的锁依赖现象,产生死锁。但是如果保证同时请求锁L和锁M的每一个线程,都是按照从 L 到 M 的顺序,那么就不会发生死锁了。 举个例子说明一下,让我们更加直观的了解顺序死锁问题,请看下面代码: public class ThreadDeadLockTest { private final Object left = new Object(); private final Object right = new Object(); public void leftRight () { synchronized (left) { synchronized (right) { doSomething(); } } } public void rightLeft () { synchronized (right) { synchronized (left) { doSomething(); } } } } 如果一个线程调用了 leftRight, 另一个线程调用了 rightLeft,这样的交替运行,那么它们会发生死锁。线程 A 拿到了left锁,而线程 B 拿到了

ReentrantLock与synchronized的区别

匿名 (未验证) 提交于 2019-12-02 21:53:52
1、 与synchronized相比,ReentrantLock提供了更多,更加全面的功能,具备更 强的扩展性。 例如:时间锁等候,可中断锁等候,锁投票。 2 、ReentrantLock还提供了条件Condition ,对线程的等待、唤醒操作更加详细和 灵活,所以在多个条件变量和高度竞争锁的地方,ReentrantLock更加适合(以后 会阐述Condition)。 3、ReentrantLock提供了可轮询的锁请求。它会尝试着去获取锁,如果成功则继 续,否则可以等到下次运行时处理,而synchronized则一旦进入锁请求要么成功要 么阻塞,所以相比synchronized而言,ReentrantLock会不容易产生死锁些。 4、ReentrantLock支持更加灵活的同步代码块,但是使用synchronized时,只能 在同一个synchronized块结构中获取和释放。注: ReentrantLock的锁释放一定要 在finally中处理,否则可能会产生严重的后果。 5、ReentrantLock支持中断处理,且性能较synchronized会好些。 转载请标明出处: ReentrantLock与synchronized的区别 文章来源: ReentrantLock与synchronized的区别

java面试经验小结

匿名 (未验证) 提交于 2019-12-02 21:53:52
此内容偏中高级,适合有三年经验者。 1. java中wait和sleep有什么区别?多线程条件下如何保证数据安全? 答:最大区别是等待时wait会释放锁,而sleep会一直持有锁,wait通常用于线程时交,互,sleep通常被用于暂停执行。 2. java中volatile和synchronized有什么区别? 1.volatile 本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 2.volatile 仅能使用在变量级别; synchronized 则可以使用在变量、方法、和类级别的。 3.volatile 仅能实现变量的修改可见性,并不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性。 4.volatile 不会造成线程的阻塞; synchronized 可能会造成线程的阻塞。 5.volatile 标记的变量不会被编译器优化; synchronized 标记的变量可以被编译器优化。 3. 有了解java的原子类?实现原理是什么? 答:采用硬件提供原子操作指令实现的,即CAS。每次调用都会先判断预期的值是否符合,才进行写操作,保证数据安全。 4. spring主要使用了哪些?IOC实现原理是什么?AOP实现原理是什么?

Java中的String、StringBuilder、StringBuffer三者的区别

匿名 (未验证) 提交于 2019-12-02 21:53:52
Java中的String、StringBuilder、StringBuffer三者的区别 在刚开始学习的时候,对于性能啥的完全不了,一般字符串操作都是String直接加加减减,觉得能完成功能完成就好了。然后考虑到找工作了,看了点面经发现有可能会问到一些相关的问题,了解了一些。后面看了点关于虚拟机的知识,慢慢对String类型如何实现和底层是怎么样的产生了兴趣。找个机会总结一下 这篇文章的内容基本参考自网络,添加了一些自己的想法。 首先,这三者必定是Java处理String的类。那么区别是什么呢? 先简单来说,处理的效率上:StringBuilder > StringBuffer > String 线程安全来说,StringBuilder处理数据是非线程安全的,而StringBuffer是线程安全的。这点主要是从源码的角度来说的。他们两者的区别类似于HashMap和HashTable。在StringBuffer中的方法基本都是有Synchronized 关键字标记,适合在多线程环境中使用,当然因为这样,所以处理效率上比不上StringBuilder。 1、String类 展开一下String类,String类在Java中是不可变类,不可变指的是任何对String类型的改变都基本上是创建一个新的String对象,然后将这个新的对象的引用传递回来,这个步骤由JVM实现

java设计模式

匿名 (未验证) 提交于 2019-12-02 21:53:52
转载原地址: https://blog.csdn.net/a394268045/article/details/51801258 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下: 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化