1.jdk提供的默认类加载器:
-
bootstrap classloader(它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar 或 sun.boot.class.path 路径下的内容)),extensionclassloader(用来加载Java的扩展库(JAVA_HOME/jre/lib/ext/*.jar或 java.ext.dirs路径下的内容) ),application classloader(Java应用的类都是由它来完成加载的)。
-
作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。
-
双亲委派模型工作过程:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。
为什么需要双亲委派模型?
试想一个场景:
| 黑客自定义一个java.lang.String类,该String类具有系统的String类一样的功能,只是在某个函数稍作修改。比如equals函数,这个函数经常使用,如果在这这个函数中,黑客加入一些“病毒代码”。并且通过自定义类加载器加入到JVM中。此时,如果没有双亲委派模型,那么JVM就可能误以为黑客自定义的java.lang.String类是系统的String类,导致“病毒代码”被执行。 |
而有了双亲委派模型,黑客自定义的java.lang.String类永远都不会被加载进内存。因为首先是最顶端的类加载器加载系统的java.lang.String类,最终自定义的类加载器无法加载java.lang.String类。或许你会想,我在自定义的类加载器里面强制加载自定义的java.lang.String类,不去通过调用父加载器不就好了吗?确实,这样是可行。但是,在JVM中,判断一个对象是否是某个类型时,如果该对象的实际类型与待比较的类型的类加载器不同,那么会返回false。
2.volatile关键字:
- 保证内存可见性(但不保证操作的原子性)。
- 防止指令重排(在指令序列中插入内存屏障)。
-下面是基于保守策略的JMM内存屏障插入策略:
在每个volatile写操作的前面插入一个StoreStore屏障。
在每个volatile写操作的后面插入一个StoreLoad屏障。
在每个volatile读操作的前面插入一个LoadLoad屏障。
在每个volatile读操作的后面插入一个LoadStore屏障。
3.volatile和synchronized的区别:
- volatile不会进行加锁操作,volatile变量是一种比synchronized关键字更轻量级的同步机制。
- volatile不如synchronized安全
- volatile无法同时保证内存可见性和原则性
- 当且仅当满足以下所有条件时,才应该使用volatile变量:
①对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
②该变量没有包含在具有其他变量的不变式中。
4.线程池初始化参数:
- corePoolSize:线程池的大小
- maximumPoolSize:线程池中创建的最大线程数
- keepAliveTime:空闲的线程多久时间后被销毁
- workQueue:阻塞队列
- handler:线程拒绝策略,当创建的线程超出maximumPoolSize,且缓冲队列已满时,新任务会拒绝,有以下取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
5.ReentrantLock和synchronized使用分析
ReentrantLock是Lock的实现类,是一个互斥的同步器,在多线程高竞争条件下,ReentrantLock比synchronized有更加优异的性能表现。
1 用法比较
- Lock使用起来比较灵活,但是必须有释放锁的配合动作
- Lock必须手动获取与释放锁,而synchronized不需要手动释放和开启锁
- Lock只适用于代码块锁,而synchronized可用于修饰方法、代码块等
2 特性比较
- ReentrantLock的优势体现在:
- 具备尝试非阻塞地获取锁的特性:当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁
- 能被中断地获取锁的特性:与synchronized不同,获取到锁的线程能够响应中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会被释放
- 超时获取锁的特性:在指定的时间范围内获取锁;如果截止时间到了仍然无法获取锁,则返回
3 注意事项
- 在使用ReentrantLock类的时,一定要注意三点:
- 在finally中释放锁,目的是保证在获取锁之后,最终能够被释放
- 不要将获取锁的过程写在try块内,因为如果在获取锁时发生了异常,异常抛出的同时,也会导致锁无故被释放。
- ReentrantLock提供了一个newCondition的方法,以便用户在同一锁的情况下可以根据不同的情况执行等待或唤醒的动作。