0512
1. 单例与序列化:<http://www.hollischuang.com/archives/1144>
-
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的方式 。 HashMap 实现 Iterator,支持fast-fail,Hashtable的 Iterator 遍历支持fast-fail,用 Enumeration 不支持 fast-fail
-
HashMap 和 ConcurrentHashMap 的区别?
ConcurrentHashMap和HashMap的实现方式不一样,虽然都是使用桶数组实现的,但是还是有区别,ConcurrentHashMap对桶数组进行了分段,而HashMap并没有。ConcurrentHashMap在每一个分段上都用锁进行了保护。HashMap没有锁机制。所以,前者线程安全的,后者不是线程安全的。
PS:以上区别基于jdk1.8以前的版本。
-
CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。
-
当讨论集合时,考虑哪些方面?
- 集合数据结构、组织方式,和类型名称对称:set、map、list、array等
- 集合使用方法(读写):插、删、改、读;性能思考,空间时间,结合数据结构分析
- 线程安全性:多线程、并发等
-
-
lazy loading,性能影响
-
类加载机制
-
使用到的关键字:static,synchronized(线程安全考虑),static final
-
懒汉、饿汉、双重校验锁、枚举、内部静态类
- 懒汉:直到第一次被使用才实例化一个对象,用if语句判断是否已经存在一个实例,多线程环境中不安全,使用synchronized关键字,同步方法;同步方发块就成了双重校验锁;此时隐患与JMM有关,volatile关键字
5.单例和反序列化,objectstream(objectinputstream:write、objectoutputstream:readObject) ,反序列化破坏单例 <-- 通过序列化将对象以文件方式保存,然后需要的时候读取文件流获取对象
-
-
Java内存模型、内存结构、:http://www.hollischuang.com/archives/1003 、http://www.hollischuang.com/archives/2509
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a5YYIer5-1634177624652)(http://www.hollischuang.com/wp-content/uploads/2018/06/QQ20180624-150918.png"java内存结构")]
jvm内存结构
Java的多线程之间是通过共享内存进行通信的,而由于采用共享内存进行通信,在通信过程中会存在一系列如可见性、原子性、顺序性等问题,而JMM就是围绕着多线程通信以及与其相关的一系列特性而建立的模型。JMM定义了一些语法集,这些语法集映射到Java语言中就是volatile、synchronized等关键字。
这里就不对Java内存模型做更加详细的介绍了,想了解更多的朋友可以参考**《Java并发编程的艺术》**。
- 在Java中提供了一系列和并发处理相关的关键字,比如
volatile
、synchronized
、final
、concurren
包等。其实这些就是Java内存模型封装了底层的实现后提供给程序员使用的一些关键字。http://www.hollischuang.com/archives/2550 - 并发编程:多线程,考虑线程安全(线程通信和同步)、效率;代码可见性、原子性、,多线程,考虑数据同步,底层一点的就是内存模型,JMM是Java内存模型,顺序一致性模型,通过JMM模型保证同步的程序能正确运行。
- 可见性、重排性、可读性
=0513======
05-14 多线程、JMM、内存模型相关
- 顺序一致性模型、JMM
- 注意:**顺序一致性模型、JMM都是一种抽象的模型概念。**在顺序一致性模型中,所有操作完全按程序的顺序串行执行。而在 JMM 中,临界区内的代码可以重排序(但 JMM 不允许临界区内的代码“逸出”到临界区之外,那样会破坏监视器的语义)
- 多线程中,没有同步操作,会造成数据竞争
- JMM做到的:正确同步的程序,程序的执行将具有顺序一致性(sequentially consistent)-- 即程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同(马上我们将会看到,这对于程序员来说是一个极强的保证)。这里的同步是指广义上的同步,包括对常用同步原语(lock,volatile 和 final)的正确使用。
- 自己的话:同步、顺序一致性:JMM只保证顺序一致性,不进行同步(synchronized关键字,程序员自己使用),在临界区内可以进行指令重排序,提高编译、执行效率
- volatile 变量自身具有下列特性:
- 可见性。对一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile 变量最后的写入。
- 原子性:对任意单个 volatile 变量的读 / 写具有原子性,但类似于 volatile++ 这种复合操作不具有原子性。
- 当读一个 volatile 变量时,JMM 会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。
- 写:在写入本地内存的同时,写入到共享内存中。volatile是在多线程编程中使用到的关键字,结合实际情况解释更加清楚,在1的基础上,我们讲写一个volatile变量的语义就是:
- 线程 A 写一个 volatile 变量,实质上是线程 A 向接下来将要读这个 volatile 变量的某个线程发出了(其对共享变量所在修改的)消息。
- 线程 B 读一个 volatile 变量,实质上是线程 B 接收了之前某个线程发出的(在写这个 volatile 变量之前对共享变量所做修改的)消息。
- 线程 A 写一个 volatile 变量,随后线程 B 读这个 volatile 变量,这个过程实质上是线程 A 通过主内存向线程 B 发送消息。
- ;锁:ReentrantLock
- final:
- 在构造函数内对一个 final 域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
- 初次读一个包含 final 域的对象的引用,与随后初次读这个 final 域,这两个操作之间不能重排序。
- 读 final 域的重排序规则如下:
- 在一个线程中,初次读对象引用与初次读该对象包含的 final 域,JMM 禁止处理器重排序这两个操作(注意,这个规则仅仅针对处理器)。编译器会在读 final 域操作的前面插入一个 LoadLoad 屏障。
- 关键字:volatile,synchronized,等,在多线程使用
- 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题
- 字符串工具类:StringUtils
- string、stringbuilder、stringbuffer
05-15
-
-
Java中的类装载到JVM才能运行,使用ClassLoader类、loadClass方法、Java使用双亲委派模型。实质上就是,从硬盘读取到内存中。Java虚拟机就是内存管理环境。《== loadClass方法理解为,类读取到jvm的第一步??
-
类装载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件,在java中类装载器把一个类装入JVM,经过以下步骤:
1、装载:查找和导入Class文件 2、链接:其中解析步骤是可以选择的 (a)检查:检查载入的class文件数据的正确性 (b)准备:给类的静态变量分配存储空间 (c)解析:将符号引用转成直接引用 3、初始化:对静态变量,静态代码块执行初始化工作
-
类加载方式并不是所有都使用双亲委派模式,例如
Apache Tomcat
(Java web容器)为每个Web
应用都提供一个独立的类加载器,使用的就是自己优先加载的策略。IBM WebSphere Application Server
则允许Web应用选择类加载器使用的策略。
-
-
内存模型是怎么解决缓存一致性问题的? 缓存一致性:MESI的核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取
-
既然在硬件层面,已经有了缓存一致性协议,可以保证缓存的一致性即并发编程中的可见性,那么为什么在写多线程的代码的时候,程序员要自己使用volatile、synchronized等关键字来保证可见性?
05-18
-
现在使用的技术,总的来说就是:框架(springboot常见)+数据库(关系型:Mybatis etc、非关系型:Redis etc)
-
spring boot:框架中已经包含了ioc、aspect、context、orm、jdbc、mvc(MVC框架:model,View、Controller)等。。使用pom.xml导入依赖包,使用配置文件,
-
泛型
- 类型擦除特点,所有的泛型类型实例在Java中都指向一份字节码,由于经过类型擦除,所有的泛型类实例都关联到同一份字节码上,泛型类的所有静态变量是共享的。所以,重载函数中仅泛型的类型不同,不能视为方法签名改变、异常捕获也不能按照类型捕获。
- 上下界通配符 extends、super;泛型做方法参数时,extends只能get,super只能写
-
单元测试、常用工具类(StringUtil、DateUtil):使用工具类保证线程安全、正则表达式
-
异常:Exception、Error
- Exception和 Error, ⼆者都是 Java异常处理的重要⼦类, 各⾃都包含⼤量⼦类。均继承自Throwable类。
- Error表⽰系统级的错误, 是java运⾏环境内部错误或者硬件问题, 不能指望程序来处理这样的问题, 除了退出运⾏外别⽆选择, 它是Java虚拟机抛出的。
- Exception 表⽰程序需要捕捉、 需要处理的常, 是由与程序设计的不完善⽽出现的问题, 程序必须处理的问题。
-
Spring 中使用了哪些设计模式?
- 工厂模式: spring中的BeanFactory就是简单工厂模式的体现,根据传入唯一的标识来获得bean对象;
- 单例模式: 提供了全局的访问点BeanFactory;
- 代理模式: AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)
- 装饰器模式: 依赖注入就需要使用BeanWrapper;
- 观察者模式: spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
- 策略模式: Bean的实例化的时候决定采用何种方式初始化bean实例(反射或者CGLIB动态字节码生成)
作者:敖丙
链接:https://juejin.im/post/5ec0ff4a6fb9a043271c76e9 面经
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
-
动态代理:
- JDK:类本身支持proxy接口,实现接口方法
- CGLib;
-
Mybatis:Mybatis通过动态代理使Mapper(sql映射器)接口能运行起来即为接口生成代理对象将sql查询到结果映射成pojo
0519
-
线程安全的类,线程不安全的类
-
SimpleDateFormat:线程不安全的类。,SimpleDateFormat主要可以在String和Date之间做转换,还可以将时间转换成不同时区输出。同时提到在并发场景中SimpleDateFormat是不能保证线程安全的,需要开发者自己来保证其安全性。
主要的几个手段有改为局部变量、使用synchronized加锁、使用Threadlocal为每一个线程单独创建一个等。
-
ThreadLocal
-
Java采用Big Endian来存储数据、C\C++采用Little Endian。在网络传输一般采用的网络字节序是BIG-ENDIAN。和Java是一致的。Big Endian 是指低地址端 存放 高位字节。 Little Endian 是指低地址端 存放 低位字节。
-
自动拆装箱:
- Integer i = Integer.valueOf(10);
int n = i.intValue();
- Integer i = Integer.valueOf(10);
-
线程池:
-
接口Executor->接口ExceutorService->ThreadPoolExecutor(默认实现类)
-
Executors为Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类提供了一些工具方法。Executors 可以用于方便的创建线程池。
// 工具类Executors使用默认实现类ThreadPoolExecutor创建线程池 ExecutorService pool = Executors.newCachedThreadPool();
=07-30=======
-
07-30
-
阅读源代码
- String
- Integer
- Long
- Enum
- BigDecimal
- ThreadLocal
- ClassLoader & URLClassLoader
- ArrayList & LinkedList
- HashMap & LinkedHashMap & TreeMap & CouncurrentHashMap
- HashSet & LinkedHashSet & TreeSet
-
-
java.util.concurrent、
-
显示的锁都实现了java.util.concurrent.Lock接口,主要有两个实现类:
- ReentrantLock - 比synchronized稍微灵活一些的重入锁
- ReentrantReadWriteLock - 在读操作很多写操作很少时性能更好的一种重入锁
-
CountDownLatch、semephore、ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue来实现生产者-消费者并发模型
-
-
-
线程、多线程、线程池、java.util.concurrent并发工具包:
t.none-task-blog-BlogCommendFromMachineLearnPai2-6.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.channel_param) -
线程、多线程、线程池、java.util.concurrent并发工具包:
-
锁:synchronized、CountDownLatch、semephore、重入锁:reent’rantlock、Conditon、JUC:callable,future、CAS
-