一. Lock锁
1. ReentrantLock
ReentrantLock:重入锁 和synchronized作用一致
lock(); //上锁
unLock(); //开锁
- 用起来更加的自由和方便
- 关键字synchronized定义的代码块或者方法中如果出现异常,会自动释放锁
- Lock如果上锁后出现异常,不会释放锁
- 必须使用try-finally释放锁
package day24;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo01 {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
//买一把锁 一把重入锁
Lock lock = new ReentrantLock();
int count = 100;
@Override
public void run() {
while(true) {
try {
//上锁
lock.lock();
if(count<=0) {
break;
}
System.out.println(Thread.currentThread().getName()+"卖了第"+count+"票");
count--;
} finally {
//开锁
lock.unlock();
}
}
}
};
ExecutorService es = Executors.newCachedThreadPool();
for(int i=1; i<=3; i++) {
es.submit(runnable);
}
es.shutdown();
}
}
2. 读写锁
package day24;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
public class Demo02 {
public static void main(String[] args) {
ReadAndWrite rw = new ReadAndWrite();
Runnable r1 = new Runnable() {
@Override
public void run() {
rw.write("dd");
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
String s = rw.read();
System.out.println(s);
}
};
ExecutorService es = Executors.newCachedThreadPool();
//三个线程写入
for(int i=0; i<3; i++) {
es.submit(r1);
}
//四个线程读入
for(int i=0; i<4; i++) {
es.submit(r2);
}
/*
* 读锁 和 写锁 的关系
*
* 写 写 互斥
* 写 读 互斥
*
* 读 写 互斥
* 读 读 不互斥
*
* 所有的目的:都是提高执行的效率
*/
}
}
class ReadAndWrite {
//重入读写锁
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
//读锁
ReadLock readLock = lock.readLock();
//写锁
WriteLock writeLocl = lock.writeLock();
String str;
/*
* 如果使用synchronized关键对方法进行加锁
* 锁的对象,就是调用该方法的对象
*
* 如果一个线程获取了该对象锁,执行write方法
* 其他任何线程都不能获取到该对象锁,执行该对象中的方法
* public synchronized void write(String s) {}
*/
public void write(String s) {
readLock.lock();
str += s;
readLock.unlock();
}
public String read() {
writeLocl.lock();
//读取业务----
writeLocl.unlock();
return str;
}
}
3. 线程安全集合
-
CopyOnWriteArrayList
-
线程安全的ArrayList,加强版读写分离。
写有锁,读⽆锁,读写之间不阻塞,优于读写锁。
写⼊时,先copy⼀个容器副本、再添加新元素,最后替换引⽤。
使⽤⽅式与ArrayList⽆异。
-
Vector 线程安全的,底层是数组
-
//CopyOnWriteArrayList中写入,读取的方法 写有锁,读没有锁
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//添加互斥锁
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
public E get(int index) {
return get(getArray(), index);
}
//Vector
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
- CopyOnWriteArraySet
- 线程安全的Set,底层使⽤CopyOnWriteArrayList实现。
- 写有锁,读无锁
- ConcurrentHashMap
- 线程安全的Map集合
- 初始容量默认为16段(Segment),使⽤分段锁设计
- 不对整个Map加锁,⽽是为每个Segment加锁
- 当多个对象存⼊同⼀个Segment时,才需要互斥。
- Hashtable
- 也是一个线程安全的Map集合
- 使用方法添加synchronized,实现的线程安全
- Map
- HashMap 线程不安全
- Hashtable 线程安全
- ConcurrentHashMap 线程安全
package com.qf;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
public class Demo03 {
public static void main(String[] args) {
//线程安全的List集合,读写分离 写有锁 读没有锁 相互不阻塞
List<String> list = new CopyOnWriteArrayList<String>();
//线程安全的List集合,方法加锁
List<String> list2 = new Vector<String>();
//线程安全的map集合 分段加锁(16个元素为一段)
Map<String,String> map = new ConcurrentHashMap<String, String>();
//线程安全的map集合 所有方法加锁
Map<String,String> map2 = new Hashtable<String, String>();
//线程安全的set集合 底层是CopyOnWriteArrayList
Set<String> set = new CopyOnWriteArraySet<String>();
}
}
4. 队列
Collection的⼦接⼝,表示队列FIFO(First In First Out)。
public interface Queue<E> extends Collection<E> {
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E peek();
}
package day24;
import java.util.LinkedList;
import java.util.Queue;
public class Demo04 {
public static void main(String[] args) {
/*
* 队列: 遵循先进先出
* 选择类名或者接口名,点击Ctrl+t 可以该类及接口的继承和实现情况
*
*/
Queue<String> queue = new LinkedList<String>();
//添加元素
queue.offer("熊大");
queue.offer("熊二");
queue.offer("熊三");
queue.offer("熊四");
int size = queue.size();
System.out.println(size);
//获取元素 并删除
for(int i=0; i<size; i++) {
String value = queue.poll();
System.out.println(value + "---队列中还剩"+queue.size()+"个元素");
}
}
}