目录
Synchronized原理
Synchronized的优化手段
锁膨胀/锁升级
体现了Synchronized能够“自适应”这样的能力。
 
锁粗化
粗化的反面是细化
 此处的粗细指的是“锁的粒度”。指的是加锁代码涉及到的范围。加锁代码的范围越大,认为锁的粒度越粗,范围越小,则认为粒度越细。
 
 到底锁的粒度是粗好还是细好?各有各的好
 如果锁的粒度比较细,多个线程之间的并发性就更高
 如果锁的粒度比较粗,加锁解锁的开销就更小
 编译器就会有一个优化,就会自动判定说,如果某个地方的代码锁的粒度太细了,就会进行粗化。
锁消除
有些代码,不用加锁,结果给加锁了。编译器就会发现这个加锁没必要,就直接把锁给去掉了。
 像StringBuffer 、 Vector…在标准库中进行了加锁操作,在单个线程中用到了上述的类,就是单线程进行了加锁解锁。
Java中的JUC
iava.util.concurrent
Callable 接口
Callable 是一个interface,也是一种创建线程的方式。
 Runnable创建线程,但是不太适合让线程计算出一个结果,这样的代码。
 例如:像创建一个线程,让这个线程计算1+2+3+…+1000,如果基于Runnable来实现,就会比较麻烦。
Callable就是要解决Runnable不方便返回结果这个问题的
public class Demo28 {
    public static void main(String[] args)  {
        //通过Callable来描述一个这样的任务
        Callable<Integer> callable=new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
               int sum=0;
               for(int i=0;i<=1000;i++){
                   sum += i;
               }
               return sum;
            }
        };
        //为了让线程执行callable中的任务,光有构造方法还不够,还需要一个辅助的类
        FutureTask<Integer> task=new FutureTask<>(callable);
        //创建线程。来完成这样的计算工作
        Thread t=new Thread(task);
        t.start();
        //如果线程的任务没有执行完,get就会阻塞
        //一致阻塞到,任务完成了,结果算出来了
        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
 
 
ReentrantLock
可重入锁
基础用法
提供了两种方法
 lock()
 unlock()
 把加锁和解锁两个操作分开了(这种做法不太好,很容易遗漏unlock)
public class Demo29 {
    public static void main(String[] args) {
        ReentrantLock  locker=new ReentrantLock();
        //加锁
        locker.lock();
        //如果在这里抛出异常了,就容易导致unlock执行不到
        //解锁
        locker.unlock();
    }
}
 

和Synchronized的区别
(1)Synchronized是一个关键字(背后的逻辑是JVM内部实现的,c++代码写的),ReentrantLock是一个标准库中的类(背后的逻辑是Java代码写的)。
 (2)Synchronized不需要手动释放锁,出了代码块,锁自然释放。ReentrantLock必须要手动释放锁,要谨防忘记释放。
 🎈(3)Synchronized如果竞争锁失败,就会阻塞等待,但是ReentrantLock除了阻塞等待,还会trylock,失败了直接返回。
🎈(4)Synchronized是非公平锁,ReentrantLock提供了公平锁和非公平锁两个版本,在构造方法中,通过参数来指定当前十公平还是非公平。
 (5)基于Synchronized衍生出来的等待机制是wait notify,功能相对有限; 基于ReentrantLock衍生出来的等待机制是Condition类,功能要更丰富一系。
信号量 Semaphore
是一个更广义的锁
 锁是信号量里一种特殊情况,叫做“二次元信号量”。
public class Demo30 {
    public static void main(String[] args) throws InterruptedException {
        //初始化的值表示可用资源有4个
        Semaphore semaphore=new Semaphore(4);
        //申请资源  P操作
        semaphore.acquire();
        System.out.println("申请成功");
        semaphore.acquire();
        System.out.println("申请成功");
        semaphore.acquire();
        System.out.println("申请成功");
        semaphore.acquire();
        System.out.println("申请成功");
        semaphore.acquire();
        System.out.println("申请成功");
        //释放资源,V操作
        //semaphore.release();
    }
}
 
CountDownLatch
类似于终点线

public class Demo31 {
    public static void main(String[] args) throws InterruptedException {
        //构造方法的参数表示有几个选手参赛
        CountDownLatch latch=new CountDownLatch(10);
        for(int i=0;i<10;i++){
            Thread t=new Thread(() ->{
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName()+"跑完了");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }) ;
            t.start();
        }
        //裁判就要等待所有的线程到达
        //当这些线程没有执行完的时候,await就阻塞,所有的线程都执行完了,await才返回
        latch.await();
        System.out.println("比赛结束");
    }
}
 
 
copyOnWriteArrayList
写时拷贝,在修改的时候,会创建一个副本出来。
 适合于读多写少的情况,也适合于数据小的情况
多线程下使用哈希表
HashMap本身线程不安全
 1.HashTable 【不推荐】
 HashTable 是如何保证线程安全的?就是给关键方法加锁


2.ConcurrentHashMap
 
 ConcurrentHashMap改进之处
 (1)ConcurrentHashMap减少了锁冲突,就是让锁加到每个链表的头节点上
 (2)ConcurrentHashMap只是针对写操作加锁了,读操作没加锁,只是使用Volatile
 (3)ConcurrentHashMap中更广泛的使用CAS,进一步提高效率
 (4)ConcurrentHashMap针对扩容,进行了巧妙的化整为零
 对于HashTable来说,只要这次put触发了扩容就一口气搬运完,会导致这次put非常卡顿。对于ConcurrentHashMap,每次操作只搬运一点点,通过多次操作完成整个搬运的过程。
 同时维护一个新的HashMap和一个旧的,查找的时候既需要查找旧的,也需要查找新的,插入的时候只插入新的,直到搬运完在销毁旧的。










