线程创建形式

  1. 继承ThreadLocal
  2. 实现Runnable
  3. 实现Callable:有返回值的任务,用Future接受返回值
  4. 使用线程池ExecutorService实现
    1. newCachedThreadPool 不定长线程池
    2. newFixedThreadPool 定长线程池
    3. newScheduledThreadPool 定时线程池
    4. newSingleThreadExecutor 串行线程池

sleep() 和 wait()

Synchronized使用方法

ThreadLocal

通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。JDK中提供的ThreadLocal类正是为了解决这样的问题。 ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。

ThreadLocal 内存泄露问题:

ThreadLocal,中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用。所以,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候会key会被清理掉,而value不会被清理掉。
在调用set()、get()、remove() 方法的时候,会清理掉keynull的记录。

乐观锁

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。

版本号机制

每次修改一个数据,一般是在数据表中加上一个数据版本号version字段。操作示意如下:

  1. 数据库里有金额100,version=1
  2. A读取金额100,修改金额为50,修改version=2
  3. B读取金额为100,修改金额为60,修改version=2
  4. A提交到库,这时有一个判断,如果当前version>库里的version,那么通过,A可以通过
  5. 由于A修改了库version=2,B的version没有大于2,被驳回,不可提交

CAS

CAS 适合简单对象的操作,比如布尔值、整型值等。
内部保持着一个volatile修饰的long变量,volatile保证了long的值更新后,其他线程能立即获得最新的值。
自旋锁,比较交换算法,需要读写的内存值V,进行比较的值A,拟写入的值B

  1. 如果A取到的Value为1,要对value进行加1操作,设置期望值为2
  2. 如果B取到的Value为1,要对value进行+1,设置期望值为2
  3. A判断value+1为2,与期望值相等,那么修改Value为2
  4. B判断实际的V+B=3,与期望的2不相等,那么返回失败,继续第二步,这时读出的Value为2,循环一次。

悲观锁

传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
Java中synchronizedReentrantLock等独占锁就是悲观锁思想的实现。

可重入锁

不可重入锁

AQS实现原理

避免死锁

分布式锁

分布式锁的redis实现方式