理論:
火鍋店歡迎阻塞
去銀行排隊不得不阻塞
阻塞隊列
做蛋糕,有沒有貨,和櫃子滿不滿
爲什麼用
架構
繼承關係
collection—>queue->七個阻塞隊列接口
三個紅色是重點一個粉色需注意
接近無界(21億)
synchronousQueue是生產一個,沒消費不會再生產,故爲不儲存(貝克漢姆球鞋)
最後一個注意拼寫(deque)
阻塞隊列知道嗎
所有用法API
異常用法
element()是檢查隊頭元素是誰
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
BlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.add("1"));
System.out.println(queue.add("2"));
System.out.println(queue.add("3"));
//System.out.println(queue.add("6"));
System.out.println(queue.element());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
//System.out.println(queue.remove());
}
}
特殊值用法(也就是布爾值)
peek()是查看隊列頂端元素
offer添加超過隊長返回false
pull拿值無值返回null
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class BlockingQueueDemo2 {
public static void main(String[] args) {
BlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
try {
System.out.println(queue.offer(1,1, TimeUnit.SECONDS));
System.out.println(queue.offer(2,1, TimeUnit.SECONDS));
System.out.println(queue.offer(3,1, TimeUnit.SECONDS));
System.out.println(queue.offer(4,1, TimeUnit.SECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println();
System.out.println(queue.peek());
System.out.println();
try {
System.out.println(queue.poll(1,TimeUnit.SECONDS));
System.out.println(queue.poll(1,TimeUnit.SECONDS));
System.out.println(queue.poll(1,TimeUnit.SECONDS));
System.out.println(queue.poll(1,TimeUnit.SECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
阻塞
不夠加入或者取不到值就一直阻塞線程
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class BlockingQueueDemo3 {
public static void main(String[] args) {
BlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
try {
queue.put(1);
queue.put(2);
queue.put(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
//System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
超時
隊列超了等幾秒,如果還超就返回false
隊列取不到值了就等幾秒,如果還取不到值就返回null
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class BlockingQueueDemo3 {
public static void main(String[] args) {
BlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
try {
System.out.println(queue.offer(1, 1, TimeUnit.SECONDS));
System.out.println(queue.offer(1, 1, TimeUnit.SECONDS));
System.out.println(queue.offer(1, 1, TimeUnit.SECONDS));
System.out.println(queue.offer(1, 1, TimeUnit.SECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println(queue.poll(2,TimeUnit.SECONDS));
System.out.println(queue.poll(2,TimeUnit.SECONDS));
System.out.println(queue.poll(2,TimeUnit.SECONDS));
System.out.println(queue.poll(2,TimeUnit.SECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
錢多事少離家近,別人加班你加薪
synchronousQueue的理論
import java.sql.Time;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<Object> queue = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"put1");
queue.put(1);
System.out.println(Thread.currentThread().getName()+"put2");
queue.put(2);
System.out.println(Thread.currentThread().getName()+"put3");
queue.put(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"AAA").start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"get1");
System.out.println(queue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"get2");
System.out.println(queue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"get3");
System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"BBB").start();
}
}
同步隊列不存儲元素,第一個put完必須等take過後纔打印,put2,而不是直接打印
只能有一個在隊列裏面
所有腦圖
生產者消費者模式
高內聚低耦合的情況下線程操縱資源類
判斷幹活喚醒通知
嚴防多線程併發狀態下的虛假喚醒
多線程判斷要用while防止虛假喚醒(juc裏面的知識可以回顧)
傳統版的生產者消費者模式代碼
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class shareDate {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment() {
lock.lock();
try {
//判斷
while (number != 0) {
//不能生產
condition.await();
}
//生產
number++;
System.out.println(Thread.currentThread().getName() + "線程 \t" +number+ "生產");
//喚醒
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
//判斷
while (number == 0) {
//不能消費
condition.await();
}
//消費
number--;
System.out.println(Thread.currentThread().getName() + "線程 \t" +number+ "消費");
//喚醒
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ProductConsumerDemo {
public static void main(String[] args) {
shareDate shareDate = new shareDate();
new Thread(()->{
for (int i = 1; i <= 5 ; i++) {
shareDate.increment();
}
},"AAA").start();
new Thread(()->{
for (int i = 1; i <= 5 ; i++) {
shareDate.decrement();
}
},"BBB").start();
new Thread(()->{
for (int i = 1; i <= 5 ; i++) {
shareDate.increment();
}
},"CCC").start();
new Thread(()->{
for (int i = 1; i <= 5 ; i++) {
shareDate.decrement();
}
},"DDD").start();
}
}
sync和lock的區別
sync兩次退出,第一次正常退出第二次異常退出
之前敲過
代碼
package juc;
import sun.awt.windows.ThemeReader;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class ShareResource{
private int flag = 1;
private ReentrantLock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
//ctrl+alt+t是try catch
public void print5(int totalLoop){
lock.lock();
try {
//1.判斷
while (flag != 1){
condition1.await();
}
//幹活
for (int i = 1;i <= 5; i++) {
System.out.println("線程名字:"+Thread.currentThread().getName()+"\t次數:"+i+"\t輪數:"+totalLoop);
}
//喚醒+通知
flag = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print10(int totalLoop){
lock.lock();
try {
//1.判斷
while (flag != 2){
condition2.await();
}
//幹活
for (int i = 1;i <= 10; i++) {
System.out.println("線程名字:"+Thread.currentThread().getName()+"\t次數:"+i+"\t輪數:"+totalLoop);
}
//喚醒+通知
flag = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print15(int totalLoop){
lock.lock();
try {
//1.判斷
while (flag != 3){
condition3.await();
}
//幹活
for (int i = 1;i <= 15; i++) {
System.out.println("線程名字:"+Thread.currentThread().getName()+"\t次數:"+i+"\t輪數:"+totalLoop);
}
//喚醒+通知
flag = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ConditionLockDemo {
public static void main(String[] args) {
ShareResource sr = new ShareResource();
new Thread(()->{
for(int i = 1 ; i<=10 ; i++){
sr.print5(i);
}
},"A").start();
new Thread(()->{
for(int i = 1 ; i<=10 ; i++){
sr.print10(i);
}
},"B").start();
new Thread(()->{
for(int i = 1 ; i<=10 ; i++){
sr.print15(i);
}
},"C").start();
}
}
代碼編寫時應注意:
通順,適配,通用
傳藉口不允許傳具體的類
寫往抽象寫,查往仔細落地查
永遠傳參傳接口
阻塞隊列版的生產者消費者模式代碼
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
class ProductConsumer {
private volatile boolean FLAG = true;
private AtomicInteger atomicInteger = new AtomicInteger();
private BlockingQueue<String> blockingQueue = null;
public ProductConsumer(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
}
public void increment() throws Exception {
String date = null;
boolean retValue;
while (FLAG) {
date = atomicInteger.incrementAndGet() + "";
retValue = blockingQueue.offer(date, 2L, TimeUnit.SECONDS);
if (retValue) {
System.out.println(Thread.currentThread().getName() + "\t" + date + "生產一個蛋糕");
} else {
System.out.println(Thread.currentThread().getName() + "\t" + date + "生產一個失敗");
}
TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName()+"boss暫停不生產了");
}
public void decrement() throws Exception {
String result = null;
while (FLAG) {
result = blockingQueue.poll(2L, TimeUnit.SECONDS);
if(null == result || result.equalsIgnoreCase("")){
FLAG = false;
System.out.println(Thread.currentThread().getName()+"超過兩秒沒有取出蛋糕暫停");
return;
}
System.out.println(Thread.currentThread().getName()+"消費蛋糕成功");
}
}
public void stop(){
this.FLAG = false;
}
}
public class ProductConsumerBlockingQueue {
public static void main(String[] args){
ProductConsumer productConsumer = new ProductConsumer(new ArrayBlockingQueue<>(10));
new Thread(()->{
try {
System.out.println("生產線程啓動");
for (int i = 1; i <= 5 ; i++) {
productConsumer.increment();
}
} catch (Exception e) {
e.printStackTrace();
}
},"prod").start();
new Thread(()->{
try {
System.out.println("消費線程啓動");
for (int i = 1; i <= 5 ; i++) {
productConsumer.decrement();
}
} catch (Exception e) {
e.printStackTrace();
}
},"consumer").start();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("boss叫停");
productConsumer.stop();
}
}