1、synchronize 是隐式锁 或者内置锁,进去的时候锁住,出来的时候释放锁。jdk 内置的,无法修改
类锁 : public static synchronized method() 静态方法+关键字 是 类锁。锁 是 .class
对象锁: public synchronized() 是对象锁。默认 锁 this。
方法锁: 在 方法里面 调用 synchronized(某个对象) 。
大概有这三种用法。
2、 ReentranceLock Syntronized 都是 可重入锁,是显式锁。在递归的时候可以反复拿锁
某个线程试图获取一个已经由它自己持有的锁,则会成功获取。重入意味着粒度是 线程 而非调用。
实现方式是:为每个锁关联一个获取计数器值和一个所有者线程。没调用一次计数加1,执行完毕,计数器减1 ,一直到 为0 。其他线程才能拿到这个锁。
优势:
第一、可以解决初始化顺序的操作。比如B线程的执行需要A线程执行的结果,就可以这样进行处理。
第二 、继承 父类的带锁的方法, 子类调用父类 造成死锁的问题。
第三 、解决 内置锁无法中断一个正在等待获取锁的线程。加锁更加灵活。
第四、 调用 trylock 方法不断轮询的方式,避免阻塞,流程可能。 获取锁之后调用 unlock 方法 去释放掉锁。
第五 、 分为公平锁 和 不公平锁 。
3、CAS 机制
CAS 全称是 Compared And Swap 是比较 和交换的意思。 不断的比较和交换 。
原子性 就是不可分的。 使用sync 实现原子性操作比较重,现在CPU 提供CAS 的方法。
Syn 悲观锁,同一时间 只有一个去改动。
CAS 乐观锁, 同一时期可以有多个线程进入。原子性操作 先比较 再交换值。
悲观锁 造成阻塞,会造成上下文切换,上下文切换 耗费 5000-20000 时钟周期,差不多 3-5ms。 cpu执行一次 cas 指令 大概 0.6ns。 cas 多次循环 也耗费cpu,比 3-5ms 要好的多。并发编程逐渐向cas或者无锁化进行偏移。大多情况下,cas好于枷锁。
自旋: 循环尝试。
CAS 不足:
ABA 问题: 解决方法是JDK 提供了 AtomicMarkableReference 和 AtomicStampedReference , 是否动过,还记录动过多少次。
自旋: 自旋长期不成功,则改用锁的方式。
原子操作的: AtomicBoolean AutomicInteger AutoMicLong AutomicReference .
线程池 和阻塞队列。 公平锁和非公平锁 Java 内存 原理机制,。
4 线程池的使用。
借助于 Executors 可以创建 newFixedThreadPool , newSingleThreadPool ,使用的BlockingQueue 都是 LinkedBlockingQueue,无边界的, 核心线程中和最大线程数一致,只使用核心线程来执行线程的操作。
newSingleThreadPool 适用于有序的串行执行耗时任务,保证单线程的执行任务。
newFixThreadPool 满足资源的要求,限制线程数量的应用场景,适用于负载比较中的服务器。
newCachedTheadPool 核心线程数 为0 , 最大线程数为无限大, 适用于短期异步任务,或者负载比较轻的服务器。 后面用的队列参数为 SynchronousQueue 容量为0 的阻塞队列, 适用于两个线程顺序的创建对象和 使用对象 ,一个线程放对象,另外一个线程取对象。可以使用 put ,take 方法代替CountDownLaunch 的阻塞,和 AutomicRefrenece 的原子型的操作。
ScehduleThreadPool 适用于 多个后台 执行周期性的任务。内部使用非核心线程数是MaxValue , DelayWorQueue 来进行定时任务的执行,可以替代Timer 和 TimerTask 存在的缺陷: 如果任务执行时间大于间隔时间或者创建线程没有处理异常。 可以处理异常,可以创建多个线程来执行任务。更好的去停止。