JUC概述
JUC
进程和线程的概念
进程:资源分配的最小单位。
线程-进程之内的独立执行的一个单元执行流
线程的状态
Wait和sleep
并发和并行
管程

用户线程和守护线程

lOCK接口
Synchronized/多线程编程步骤

- 线程间通信
什么是Lock接口

可重入锁(见后)
可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。
Synchronized 和 ReenTrantLock都是可重入锁。
ReenTrantLock()
创建线程的多种方式

虚假唤醒问题
wait()方法是在哪里睡,就在哪里醒。如下,资源类操作方法中, if语句判断,假如第一判断时,因为不满足条件所以进入wait(),但是下一次被唤醒后,不会再判断条件。造成了虚假唤醒,应该使用while语句判断。

线程间定制通信
线程执行顺序。 在多线程编程中的condition条件中,增加一个变量来控制线程执行顺序。
设计线程的执行条件,就可以实现线程的执行顺序等等操作。
ArrayList集合线程不安全
ArrayList,内部没有使用Synchronized的同步方法,它是线程不安全的。
- 并发修改异常的案例。

3种解决
第一种,不常用
第二种,不常用
第三种,常用
CopyOnWriteArrayList 写时复制技术
并发读、独立写(写时复制一份新版本,写完后合并新旧版本)。
源码
Hashset线程不安全
- 并发修改问题
CopyOnWriteArraySet 写时复制技术

HashMap线程不安全
CocurrentHashMap — 同步方法

....V oldVal = null;synchronized (f) {// 添加<key,value>... ;if (oldVal != null)return oldVal;... } // 1、 同步方法...return null; // 2、 返回null 或者 oldVal(如果存在的话)
final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh; K fk; V fv;if (tab == null || (n = tab.length) == 0)tab = initTable();else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))break; // no lock when adding to empty bin}else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f);else if (onlyIfAbsent // check first node without acquiring lock&& fh == hash&& ((fk = f.key) == key || (fk != null && key.equals(fk)))&& (fv = f.val) != null)return fv;else {V oldVal = null;synchronized (f) {if (tabAt(tab, i) == f) {if (fh >= 0) {binCount = 1;for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key, value);break;}}}else if (f instanceof TreeBin) {Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}else if (f instanceof ReservationNode)throw new IllegalStateException("Recursive update");}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal != null)return oldVal;break;}}}addCount(1L, binCount);return null;}
多线程锁
Synchronized - 锁的范围(谁作为锁)
- 是否用的同一把锁 ?
- 锁的范围 ?
- static Synchronized ?
public Synchronized void sendSMS(){
—> 锁当前对象,即this是争夺的资源
}
public static Synchronized void sendSMS(){
—> 锁当前类,即当前字节码对象this.getClass()是争夺资源
}
public void sendSMS(){
Object t = new Object();
Sysnchronized (t){
—-> 同步代码块,传入的对象t是争夺的资源。
}
}
ReentrantLock - 公平锁、非公平锁
默认: 非公平锁。
公平锁:检查前面链表节点中是否有人持有锁。
非公平锁:直接抢占。
ReentrantLock 构造器
public ReentrantLock() {sync = new NonfairSync();}public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}
NonfairSync()
initialTryLock() 尝试持有锁;
# state是锁的计数。if (compareAndSetState(0, 1)): # 原子操作, 意思是 if (state==0 ? ++state==1, false)独占线程=当前线程return true;else if (独占线程 == 当前线程):state++;return trueelsereturn false;
static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L;final boolean initialTryLock() {Thread current = Thread.currentThread();if (compareAndSetState(0, 1)) { // first attempt is unguardedsetExclusiveOwnerThread(current);return true;} else if (getExclusiveOwnerThread() == current) {int c = getState() + 1;if (c < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(c);return true;} elsereturn false;}/*** Acquire for non-reentrant cases after initialTryLock prescreen*/protected final boolean tryAcquire(int acquires) {if (getState() == 0 && compareAndSetState(0, acquires)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}}
FairSync()
# state是锁的计数。# compareAndSetState(0, 1) 原子操作, 意思是 if (state==0 ? ++state==1, false)if (hasQueuedThreads() && compareAndSetState(0, 1)):独占线程=当前线程return true;else if (独占线程 == 当前线程):state++;return trueelsereturn false;
public final boolean hasQueuedThreads() {for (Node p = tail, h = head; p != h && p != null; p = p.prev)if (p.status >= 0)return true;return false;}
static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;/*** Acquires only if reentrant or queue is empty.*/final boolean initialTryLock() {Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedThreads() && compareAndSetState(0, 1)) {setExclusiveOwnerThread(current);return true;}} else if (getExclusiveOwnerThread() == current) {if (++c < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(c);return true;}return false;}/*** Acquires only if thread is first waiter or empty*/protected final boolean tryAcquire(int acquires) {if (getState() == 0 && !hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}}
可重入锁
可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。
Synchronized 和 ReenTrantLock都是可重入锁。
Synchronized 自动释放锁。
ReenTranLock手动释放锁。不是释放锁的话,其他代码无法拿到锁。

各个区域加了锁,但是都是同一个锁,所以只要“能进入大门,就能进入小门”。 也叫递归锁。
public synchronized void operation(){add(); // 在同步方法内部,调用了另一个同步方法}public synchronized void add(){}
public void m() {lock.lock();lock.lock();try {// ... method body} finally {lock.unlock()lock.unlock()}}
死锁
线程间互相等待。

public class DeadLock {// 定义两个资源,作为锁。static Object obj1 = new Object();static Object obj2 = new Object();public static void main(String[] args) {new Thread(()->{synchronized (obj1){System.out.println(Thread.currentThread().getName() +"::"+ "持有锁obj1,等待锁obj2" );synchronized (obj2){System.out.println(Thread.currentThread().getName() + "::" + "获取到锁obj2");}}},"A").start();new Thread(()->{synchronized (obj2){System.out.println(Thread.currentThread().getName() +"::"+ "持有锁obj2,等待锁obj1" );synchronized (obj1){System.out.println(Thread.currentThread().getName() + "::" + "获取到锁obj1");}}},"B").start();}}
创建线程多种方式

Callable接口-多线程
比较runable
FutureTask : 使用callable接口

Thread支持runable接口构造,但不支持callable接口构造
解决办法:FutureTask
- FutureTask原理 —- 未来任务

JUC 辅助类
countDown
CyclicBarriar

Semaphore

读写锁
乐观锁、悲观锁


表锁、行锁
行锁支持并发,表锁不支持
行锁可能有死锁产生。




