线程的启动、常用方法
线程并列执行:join()
锁的概念
1.访问某一段代码,同一时间需要一个线程操作,就需要加锁 2.锁的是对象不是代码
锁的特性
1.加了synchronized 就不用了加volatile(访问不到其他线程修改的内容),因为sync保证了原子性、可见性 2.锁定方法和非锁定方法 可以同时执行
银行账户程序加锁
写加锁、读不加锁、会产生脏读、具体情况得看业务
可重入锁
1. m1方法加synchronized 、m2方法加synchronized 。方法1可以调用方法2。也就是同一个线程不断地加锁 2. 为什么?父类方法加锁,子类继承重写父类的方法也必须加锁,如果不能继承,那么父子之间的继承就死锁了
异常和锁
1. 默认情况锁会被释放,等待抢锁的会乱入
synchronized(XXX)
不能用String、Integer、Long、
synchronized
1.锁的是对象不是代码 2.this xx.class 3.锁定方法和非锁定方法 同事执行 4.锁升级四种: 无锁、偏向锁、自旋锁、重量级锁 偏向锁: 持有一个线程的id标识,判断如果是这个线程就让他进去,如果不是该线程就升级为自旋锁、自旋锁占用CPU,一直在那里循环等待处理,如果多次循环(10次)没有结果就升级为重量级锁
什么时候用自旋锁(占CPU)、什么时候用重锁(不占CPU)?
1、执行时间长的用重锁,因为重锁是不占用CPU的,因为第一个进去以后,其他的在等待队列中,等待CPU的唤醒。 2、自旋锁: 1.执行时间短 2.线程数比较少 3、重锁=OS锁 :1.执行时间长 2.线程数比较多
说明
锁只能升级、不能降级
Volatile
1.保证线程可见性: 缓存一致性协议 2.禁止指令重新排序: 双重判断单例模式必须加Volatile 3.不能保证原子性: 线程A 将0改1,线程B和C都看到了,然后修改结果变成了2,不是3
synchronized优化
1.锁的代码越少越好 --锁的细化 2.一个方法内有好多的锁, 还不如在该方法上加锁 -- 锁的粗化 3.锁定某对象obj,如果obj的属性发送改变,不影响锁的使用,但是如果obj变成另外一个对象,则锁定的对象发生改变,应该便面将锁定对象的引用变成另外的对象 -- 加final
CAS(CompareAndSet)
1.无锁优化、既: 自旋 2.Atomic.....开头的都是CAS 3.AtomicInteger incrementAndGet()(相当于count++) 4.原理: 原值、期望值、新值 如果原值 等于 期望值 设置新值,否则就重新执行一次 5.靠CPU原语支持,中间不能被打断 6.ABA问题:如何解决:加版本号,Atomic类有自带版本号的。 如果是个int、long不影响CAS结果,如果是引用就有问题。
LongAdder
1.分段锁 分段的CAS 2.- 性能: LongAdder > CAS > synchronized
ReentrantLock
1.可重入锁、可以代替synchronized 2.lock.lock() lock.unlock() 必须在finally内进行解锁 3. a.synchronized搞不定会阻塞, b.ReentrantLock可以决定自己是否阻塞: tryLock(time) 4.lockInterruptibly() 可以打断阻塞的线程 5.公平锁: new ReentrantLock(true) 线程来了不是先抢锁,而是先访问队列是否有等待的,如果有就跟着等,没有的话再去用锁 6.lock.newCondition可以创建不同的等待队列
CountDownLatch
1. 用来进行线程阻塞 2. CountDownLatch latch = new CountDownLatch(num) 3. latch.countDown() -1操作 4. latch.await() 什么时候num减少为0 就往下执行
CyclicBarrier: 循环栅栏
1.CyclicBarrier barrier = new CyclicBarrier(20,()->sout"out") 2.每满20,就处理一下
Phaser
阶段栅栏,每个阶段人都到齐了在进行下一阶段
ReadWriteLock
1. 读写锁 : 共享锁 + 排它锁 2. 互斥锁 = 排它锁 = ReentrantLock() 3. 读写锁 = ReentrantReadWriteLock() = readLock() + writeLock() 4. 读锁 = 共享锁: 读取的线程可以同步读,但是不能写,读完了才可以写 5. 写锁 = 互斥锁 = 排它锁: 只能写,不能读,写完了才可以读
semaphore
1. new Semaphone(2) 同时可以执行两个线程 2. .acquire() 阻塞到这里,当满足 Semaphone(num)中num个数,就变为0然后放行 3. .relaese() 将0变回为num 4. 限制流量。类似车道和收费站 5. new Semaphone(2, true)公平锁 里面有队列
Exchange
1. 线程交换 2. 线程1和线程2内容交换,只能2个线程交换
LockSupport
1. .park()阻塞 2. .unpark(线程)放行 3. unpark可以先于park执行 4. unpark可以直接指定线程执行
面试题
一、synichronized和ReentrantLock的不同?
synichronized
a.系统自动加锁、自动解锁、不可以出现多个不同的等待队列、没骗人进行四种锁状态的升级
ReentranLock
b.需要手动加锁、手动解锁、可以出现多个不同的等待队列(newCondition),CAS实现
二、
原文:https://www.cnblogs.com/bigdata-familyMeals/p/15121344.html