JUC全文
Lock接口
- lock需要用户手动上锁、释放锁
- 可以让等待锁的线程响应中断
- 通过Lock可以知道有没有成功获取锁
多线程编程步骤(上)
- 创建资源类,创建属性和操作方法
- 资源类,以后准备好的功能和资源的集合,封装属性和方法
- 高内聚
- 创建多个线程,调用资源类的操作方法
Synchronized
- 同步锁
- 修饰代码块、方法、静态方法、类
- 自动上锁,释放锁
- 发生异常时,会自动释放线程占有的锁,不会导致死锁
ReentrantLock
- 可重入锁,类似排队上厕所
- 卖票举例
class LTicket {
int count = 30;
//创建可重复锁
private final ReentrantLock lock = new ReentrantLock();
void sellTicket() {
try {
//上锁
lock.lock();
//卖票过程
if (count > 0) {
System.out.println(Thread.currentThread().getName() + "卖出:" + count-- + "剩下:" + count);
}
} finally { //不管有没有异常,都要解锁
//解锁
lock.unlock();
}
}
}
lock与lockInterruptibly
- 在阻塞等待获取锁的过程中
lock()不能被t2.interrupt()中断,只有当获取锁后,立即被中断lockInterruptibly()在阻塞过程中能被中断
线程间通信
多线程编程步骤(中)
- 创建资源类,创建属性和操作方法
- 在资源类的操作方法中,要进行
判断、执行、通知 - 创建多个线程,调用资源类方法
- 防止虚假唤醒问题
sync实现加一减一
- 存在虚假唤醒问题,在判断时,只会判断一次;用while循环解决
类似坐飞机,下飞机后,再次上飞机还需要做安检
class Shared {
int number = 0;
synchronized void incr() throws InterruptedException {
//判断
//执行
//用while,保证每次唤醒,都会经过判断
if (number != 0) {
//阻塞
this.wait();
}
number ++;
System.out.println(Thread.currentThread().getName() + " - " + number);
//通知
this.notifyAll();
}
synchronized void decr() throws InterruptedException {
if (number != 1) {
this.wait();
}
number --;
System.out.println(Thread.currentThread().getName() + " - " + number);
this.notifyAll();
}
}
Lock接口实现
class LShared {
int number = 0;
//创建lock
private final ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
void incr() {
try {
lock.lock();
//判断
while (number != 0) {
//等待
condition.await();
}
number ++;
System.out.println(Thread.currentThread().getName() + " - " + number);
//通知
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
void decr() {
try {
lock.lock();
while(number != 1) {
//等待
condition.await();
}
number --;
System.out.println(Thread.currentThread().getName() + " - " + number);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
线程间定制化通信
- 可以唤醒通过
condition1进行等待的线程
condition1.signal();
集合的线程安全
list
- list集合,
add方法没有Synchronized修饰,是线程不安全的
vector
- 有Synchronized关键字,jdk1.0
Collections
- 方法内做了转换
List<String> list = Collections.synchronizedList(new ArrayList<>());
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
CopyOnWriteArrayList
- 写时复制技术
- 支持并发读
- 独立写,先复制一份,写入新内容,再将新数组设置回去
List<String> list = new CopyOnWriteArrayList<>();
- add方法
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock(); //锁
try {
Object[] elements = getArray(); //获取当前数组
int len = elements.length;
//复制一份,且长度+1
Object[] newElements = Arrays.copyOf(elements, len + 1);
//增加新内容
newElements[len] = e;
//设置回去
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
- get
final Object[] getArray() {
return array;
}
- set
final void setArray(Object[] a) {
array = a;
}
HashSet
CopyOnWriteArraySet
Set<String> set = new CopyOnWriteArraySet<>();
- 构造
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
- add
public boolean add(E e) {
return al.addIfAbsent(e);
}
- addIfAbsent
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();
//判断是否存在,如果存在就不可添加
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
addIfAbsent(e, snapshot);
}
- 防止判断过程中,其他线程修改了set
private boolean addIfAbsent(E e, Object[] snapshot) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] current = getArray();
int len = current.length;
//进行比较
if (snapshot != current) {
// Optimize for lost race to another addXXX operation
int common = Math.min(snapshot.length, len);
for (int i = 0; i < common; i++)
if (current[i] != snapshot[i] && eq(e, current[i]))
return false;
if (indexOf(e, current, common, len) >= 0)
return false;
}
Object[] newElements = Arrays.copyOf(current, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
HashMap
ConcurrentHashMap
Map<String, String> map = new ConcurrentHashMap<>();
- put方法中使用的是synchronized