回顧多線程
線程的六個狀態
//獲取CPU的核數
System.out.println(
Runtime.getRuntime()
.availableProcessors()
);
//Thread 的六種狀態,枚舉
Thread.State.values()
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
操作系統層面是 5個, java 定義了 6個
wait 和 sleep區別
1.鎖的釋放
- wait釋放鎖,sleep抱着鎖睡覺,不釋放
2.使用範圍不同
- wait必須在同步代碼塊中
- sleep可以在任意一個地方睡
- 是否需要捕獲異常(wait不用捕獲異常,sleep必須捕獲異常)
3. lock
3. Synchronized 和 lock的區別
- synchronized 是內置的java關鍵字, Lock是一個java類
- Synchronized 無法判斷獲取鎖的狀態,Lock 可以判斷是否獲取到了鎖
- Synchronized 全自動釋放鎖
- lock必須手動釋放鎖,不然就是死鎖
- lock鎖有一個 tryLock的方法,可以嘗試獲取鎖(可以判斷鎖的狀態),不一定像Synchronized鎖一樣,一直阻塞下去
- Synchronized 可重入鎖,不可以中斷,非公平; lock,可重入,不可以中斷,非公平(也可以改成公平鎖),相比之下,lock比較靈活
線程中的協作問題!!(生產者和消費者的協作)
package example;
/**
* @Author lyr
* @create 2020/5/29 19:01
*/
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Resource s = new Resource();
new Thread(()->{
for(int i=0;i<10;++i) {
s.incr();
}
},"A線程").start();
new Thread(()->{
for(int j=0;j<10;++j) {
s.decr();
}
},"B線程").start();
}
static class Resource {
private int number;
// private Object monitor;
public synchronized void incr() {
while (number>0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.number++;
System.out.println("A線程 "+number);
this.notifyAll();
}
public synchronized void decr() {
while (number<=0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.number--;
System.out.println("B線程 "+number);
this.notifyAll();
}
}
}
4.線程的協作
使用Condition 的優勢!
Condition 可以代替 signal 隨機分佈,也可以是的線程有序執行,即 你可以使用 condition 精準的通知線程
有序執行。
package example;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author lyr
* @create 2020/5/29 19:01
*/
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Resource s = new Resource();
new Thread(()->{
for(int i=0;i<10;++i) {
s.printA();
}
},"A線程").start();
new Thread(()->{
for(int j=0;j<10;++j) {
s.printB();
}
},"B線程").start();
new Thread(()->{
for(int j=0;j<10;++j) {
s.printC();
}
},"C線程").start();
}
static class Resource {
private int number = 1;
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
private Condition conditionC = lock.newCondition();
public void printA() {
lock.lock();
try{
while (number!=1) {
conditionA.await();
}
System.out.println(
Thread.currentThread().getName()
);
number = 2;
conditionB.signal();
}catch (Exception ex) {
System.out.println(ex);
}finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try{
while (number!=2) {
conditionB.await();
}
System.out.println(
Thread.currentThread().getName()
);
number = 3;
conditionC.signal();
}catch (Exception ex) {
System.out.println(ex);
}finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try{
while (number!=3) {
conditionC.await();
}
System.out.println(
Thread.currentThread().getName()
);
number = 1;
conditionA.signal();
}catch (Exception ex) {
System.out.println(ex);
}finally {
lock.unlock();
}
}
}
}
copyOnWriteArrayList
copyOnwrite 採用寫入時複製,讀寫分離的方式。
只在寫操作的時候加鎖。
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();
}
}
final void setArray(Object[] a) {
array = a;
}
我們先試試在多線程中打印 操作 ArrayList
併發修改異常
package example;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* @Author lyr
* @create 2020/5/29 19:01
*/
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
List list = new ArrayList<>();
for(int i=1;i<10;++i) {
new Thread(()->{
list.add(UUID.randomUUID().toString());
System.out.println(list);
}).start();
}
}
}
null, d43b5115-f131-4a9a-8c17-685d1463c298, e3a0ddf5-1906-4b86-9367-6b2c46313139, 42143054-8fb2-4810-a6b2-73ee99325b04, f9579c0e-144b-4b28-8ee4-b0d92fb1c63d, 48d97a2c-59e1-4b96-823e-ed41aae01703, 9bfdddc9-e3df-4757-bfc0-cc62408f57d5]
[null, d43b5115-f131-4a9a-8c17-685d1463c298, e3a0ddf5-1906-4b86-9367-6b2c46313139, 42143054-8fb2-4810-a6b2-73ee99325b04, f9579c0e-144b-4b28-8ee4-b0d92fb1c63d, 48d97a2c-59e1-4b96-823e-ed41aae01703]
Exception in thread “Thread-4” Exception in thread “Thread-0” Exception in thread “Thread-3” Exception in thread “Thread-6” java.util.ConcurrentModificationException
at java.util.ArrayListItr.next(ArrayList.java:859)
at java.util.AbstractCollection.toString(AbstractCollection.java:461)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at example.Main.lambda$mainItr.checkForComodification(ArrayList.java:909)
at java.util.ArrayListmainItr.checkForComodification(ArrayList.java:909)
at java.util.ArrayListmainItr.checkForComodification(ArrayList.java:909)
at java.util.ArrayListmain$0(Main.java:19)
at java.lang.Thread.run(Thread.java:748)
如何讓集合操作安全?
- vector
- List list = Collections.synchronizedList(new ArrayList<>());
- CopyOnWriteArrayList 或者其他的一些工具類