Synchronized和ReetrantLock的进一步认识

文章目录


1.Synchroized

前提:八股看了一遍又一遍,每次看这个Synchroized都有点不同,这次把整体总结一下

  • 用处:同步代码块、同步方法
  • 对于非静态的一般上锁就是针对当前的对象实例;而对于静态的则针对的当前类的所有对象,因为对于类的信息我们是存在方法区的,JVM中只有一份。
  • 对象:一个对象在存储中,包含了对象头、实例数据、对其数据。而对象头又包含了MarkWord、类指针(指向类的信息),而对于锁这一部分,其实主要是MarWord这一部分:分代年龄(GC)、hashCode(HashMap)、标记位(这一部分标记了无锁、偏向锁、轻量级锁、重量级锁)
  • 简单说一下:无锁、偏向锁(只有一个线程)、轻量级锁(多个线程顺序执行)、重量级锁(抢锁),当然还有自旋锁,自适应自旋锁等。

所以对于锁来说,其实就是对象监视器来针对当前对象的对象头的标志位的一个抢占(对于类的话,应该是类对象吧,只有一个),主要以对象头标志抢占为主:

  • 拥有对象监视器(锁)的线程
  • 其他线程来的时候会进行cas抢锁,抢不到进到等待队列中(竞争队列、候选队列),因为可能同时有大量线程在等待队列中,所以我们将一部分线程拿到候选队列,作为下一次的锁的优先竞争者
  • Ondesk,下一次获取锁的线程,在当前线程释放锁之后,会在候选队列的一个线程中唤醒一个指定到Ondesk,然后再开始竞争,这里的竞争主要是Ondesk线程和此时正在cas的线程,所以这是竞争切换,明显不公平
  • 还有一个阻塞队列,是调用wait函数的线程,会把当前对象的锁释放,然后把当前线程放到阻塞队列中,只有其他线程进行notify唤醒,才可以重新进入等待队列的候选队列

注:
三种队列:等待队列(竞争队列+候选队列)、阻塞队列、运行的线程、下次竞争的线程

2. ReetrantLock

顺便把它讲了吧,这是JDK实现的,而上面的是内置的;并且ReentrantLock需要手动释放锁,出现异常可能会产生死锁,而Synchronized会自动释放;两者都是非公平锁+可重入锁,但是前者(lock)可以实现公平锁,并且可中断。

  • 内部最重要的可以说是AQS-队列抽象同步器
  • 继承它的内部类分别实现了公平锁、和非公平锁
  • 思想:一个是state状态 = c、一个是线程队列
  • 1.公平锁
  • 刚开始不会直接CAS抢锁
  • if c == 0
  • 判断队列是否为空,为空则cas抢锁,c = 1;否则加入队列
  • else 可重入(一般判断线程名是否相等)
  • 加入队列
  • 2.非公平锁
  • 直接cas抢锁(明显不公平)
  • if c == 0
  • cas 抢锁成功 c ==1;失败加入队列
  • else 可重入
  • 加入队列

注:可以看到其实和synchroized一样都是刚开始进行cas抢锁,明显不公平。

3. 线程池

继续--------

为什么需要?
1.可以进行重用,来任务的时候快速的启动,避免线程的销毁
2.线程池统一管理、统一分配

参数:
核心线程数量、最大线程数量、存活时间、单位、阻塞队列、拒绝策略、线程工厂

常见的几种线程池:

  • newFixedPoolThread(n,n,0,s,LinkedBlockingQuene)
  • newSinglePoolThread(1,1,0,s,LinkedBlockedQueue)
  • newCachePoolThread(0,Max_Value,60,s,SynchronousQuene)
  • newSchedulePoolThread–定时执行
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    scheduledThreadPool.schedule(new Runnable() {
     
    @Override
    public void run() {
    System.out.println("delay 3 seconds");
    }
    }, 3, TimeUnit.SECONDS);
    

工作原理:
对于新来的任务

  • 创建核心线程
  • 核心线程数量达到最大,进入队列
  • 队列满了,创建非核心线程
  • 都满了,则拒绝策略
  • 时间到了,非核心线程死亡

拒绝策略:

  • 直接丢弃
  • 丢弃 + 并抛出异常
  • 抛弃队列队首,加入当前线程
  • 调用当前任务的线程代为执行

阻塞队列:

  • LinkedBlockingQueue 无穷大
  • SynchronousQueue 不存储任何线程
  • 还有其他的就不一一列举了
上一篇:并发框架Disruptor(核心概念 入门 高性能原理-伪共享 CAS 环形数据 生产和消费模式 高级使用 )


下一篇:Redis分布式锁