volatile关键字,synchronized关键字,ThreadLocal关键字

volatile的作用:
①保证共享变量的可见性,不能保证原子性,也不能保证线程安全。
②保证所有线程在同一时刻读取到的共享变量值是一致的
③如果某个线程对volatile修饰的共享变量进行更新,那么其他线程可以立刻看到这个更新。
在JVM底层,volatile是采用内存屏障来实现的(禁止指令重排序)
内存屏障:用于实现对内存操作的顺序限制
在JDK1.5之前synchronized是一个重量级锁,JDK1.6对synchronized进行各种优化
Synchronized的作用:
1.原子性:确保线程互斥的访问同步代码
2.可见性:保证共享变量的修改能够及时可见
3.有序性:有限解决重排序问题
Synchronized是可重入锁,作用粒度是对象。
Synchronized死锁代码举例:

public class DeadLock {
    /** A锁 */
    private static String A = "A";
    /** B锁 */
    private static String B = "B";
    public static void main(String[] args) {
        new DeadLock().deadLock();
    }
    public void deadLock() {
        /**
         * 先获取A锁再获取B锁
         */
        Thread t1 = new Thread(() -> {
            synchronized (A) {
                try {
                    // 获取A锁后休眠2s
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                    // 获取B锁
                    System.out.println("thread1...");
                }
            }
        });
        /**
         * 先获取B锁再获取A锁
         */
        Thread t2 = new Thread(() -> {
            synchronized (B) {
                try {
                    // 获取B锁后休眠2s
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (A) {
                    System.out.println("thread2...");
                }
            }
        });
        t1.start();
        t2.start();
    }
}

Synchronized的实现原理:通过一个monitor的对象来完成,线程执行monitorenter指令来获取monitor的所有权,通过执行monitorexit来退出monitor的所有权

锁锁住的是什么?
偏向锁存储的是当前持有这个锁的线程ID
轻量级锁存储的的是线程栈中记录锁的指针

自旋锁:当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是立刻进入线程挂起或睡眠状态。

Synchronized的4种状态
1.无锁状态
2.偏向锁状态
3.轻量级锁状态
4.重要级锁状态
锁可以从偏向锁升级到轻量级锁,再升级为重量级锁。但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。
在JDK1.6中默认是开启偏向锁和轻量级锁的
偏向锁主要适用于单线程情况下重复获取这把锁的情况
如果在多线程并发的情况下(即线程A尚未执行完同步代码块,线程B发起了申请锁的申请),则一定会转化为轻量级锁或者重量级锁。
引入偏向锁主要目的是:为了在没有多线程竞争的情况下尽量减少不必要的轻量级锁执行路径。

偏向锁是在只有一个线程执行同步块时进一步提高性能而采取的锁优化
轻量级锁是为了在线程交替执行的时候为了提高性能的
如果是在单线程使用,则偏向锁代价最小,并且它就能解决问题,连CAS都不用做,如果出现其他线程竞争,则偏向锁就会升级为轻量级锁,如果其他线程通过一定的次数尝试对轻量锁进行加锁没有成功

优点 缺点 适用场景
偏向锁 加锁和解锁不需要额外的消耗 如果线程间存在锁竞争,会带来额外的锁撤销的消耗 适用于只有一个线程访问同步块场景
轻量级锁 竞争的线程不会阻塞 ,提高了程序的响应速度 如果始终得不到锁竞争的线程适用自旋会消耗CPU 追求响应时间,同步代码的执行速度非常快
重量级锁 线程竞争不使用自旋,不会消耗CPU 线程阻塞,响应时间比较长 适用追求吞吐量

ThreadLocal(线程本地变量副本):当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,每个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

你可能感兴趣的:(volatile关键字,synchronized关键字,ThreadLocal关键字)