1璃饱、什么是JUC
JUC:就是我們Java原生的并發(fā)包与斤,和一些常用的工具類!
java.util.concurrent、java.util.concurrent.atomic撩穿、java.util.concurrent.locks
2磷支、線程基礎(chǔ)知識(shí)回顧
使用@FunctionalInterface注解的Class都可以使用lambda表達(dá)式
一個(gè)進(jìn)程可以包含多個(gè)線程,一個(gè)進(jìn)程至少有一個(gè)線程食寡! Java程序至少有兩個(gè)線程: GC雾狈、Main
并發(fā):多個(gè)線程操作同一個(gè)資源,交替執(zhí)行的過(guò)程抵皱!
并行:多個(gè)線程同時(shí)執(zhí)行善榛!只有在多核CPU下才能完成!
所以我們使用多線程或者并發(fā)編程的目的:提高效率呻畸,讓CPU一直工作移盆,達(dá)到最高處理性能!
線程有 6 種狀態(tài)伤为,源碼中有:Thread.State
public enum State {
? ? // java能夠創(chuàng)建線程嗎咒循? 不能舶吗!
????// 新建
? ? NEW,
? ? // 運(yùn)行
? ? RUNNABLE,
? ? // 阻塞
? ? BLOCKED,
? ? // 等待
? ? WAITING,
? ? // 延時(shí)等待
? ? TIMED_WAITING,
? ? // 終止邑商!
? ? TERMINATED;
}
wait和sleep的區(qū)別:
1、wait是一個(gè)object類铐然,sleep是一個(gè)單獨(dú)的方法
正確的休眠方法:
TimeUnit.SECONDS.sleep(3);
2爽醋、sleep:抱著鎖睡得蚁署,不會(huì)釋放鎖!wait 會(huì)釋放鎖蚂四!
3光戈、wait 和 notify 是一組,一般在線程通信的時(shí)候使用遂赠!
4久妆、sleep 就是一個(gè)單獨(dú)的方法,在那里都可以用跷睦!
5筷弦、sleep 需要捕獲異常!
3抑诸、synchronized鎖
package com.coding.demo01;
// 傳統(tǒng)的 Synchronized
// Synchronized 方法 和 Synchronized 塊
/*
* 我們的學(xué)習(xí)是基于企業(yè)級(jí)的開(kāi)發(fā)進(jìn)行的烂琴;
* 1、架構(gòu):高內(nèi)聚蜕乡,低耦合
* 2奸绷、套路:線程操作資源類,資源類是單獨(dú)的
*/
public class Demo01 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? // 1层玲、新建資源類
? ? ? ? Ticket ticket = new Ticket();
? ? ? ? // 2号醉、線程操縱資源類
? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? for (int i = 1; i <=40; i++) {
? ? ? ? ? ? ? ? ? ? ticket.saleTicket();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? for (int i = 1; i <=40; i++) {
? ? ? ? ? ? ? ? ? ? ticket.saleTicket();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"B").start();
? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? for (int i = 1; i <=40; i++) {
? ? ? ? ? ? ? ? ? ? ticket.saleTicket();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"C").start();
? ? }
}
// 單獨(dú)的資源類反症,屬性和方法!
// 這樣才能實(shí)現(xiàn)復(fù)用畔派!
class Ticket{
? ? private int number = 30;
? ? // 同步鎖铅碍,廁所 =>close=>
? ? // synchronized 這是一個(gè)關(guān)鍵字
? ? public synchronized void saleTicket(){
? ? ? ? if (number>0){
? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "賣(mài)出第"+(number--)+"票,還剩:"+number);
? ? ? ? }
? ? }
}
4父虑、lock鎖
package com.coding.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* JUC之后的操作
* Lock鎖 + lambda表達(dá)式该酗!
*/
public class Demo02 {
? ? public static void main(String[] args) {
? ? ? ? // 1、新建資源類
? ? ? ? Ticket2 ticket = new Ticket2();
? ? ? ? // 2士嚎、線程操作資源類 , 所有的函數(shù)式接口都可以用 lambda表達(dá)式簡(jiǎn)化呜魄!
? ? ? ? // lambda表達(dá)式 (參數(shù))->{具體的代碼}
? ? ? ? new Thread(()->{for (int i = 1; i <= 40 ; i++) ticket.saleTicket();},"A").start();
? ? ? ? new Thread(()->{for (int i = 1; i <= 40 ; i++) ticket.saleTicket();},"B").start();
? ? ? ? new Thread(()->{for (int i = 1; i <= 40 ; i++) ticket.saleTicket();},"C").start();
? ? }
}
// 依舊是一個(gè)資源類
class Ticket2{
? ? // 使用Lock,它是一個(gè)對(duì)象
? ? // ReentrantLock 可重入鎖:回家:大門(mén) (臥室門(mén)莱衩,廁所門(mén)...)
? ? // ReentrantLock 默認(rèn)是非公平鎖爵嗅!
? ? // 非公平鎖: 不公平 (插隊(duì),后面的線程可以插隊(duì))
? ? // 公平鎖: 公平(只能排隊(duì)笨蚁,后面的線程無(wú)法插隊(duì))
? ? private Lock lock = new ReentrantLock();
? ? private int number = 30;
? ? public void saleTicket(){
? ? ? ? lock.lock(); // 加鎖
? ? ? ? try {
? ? ? ? ? ? // 業(yè)務(wù)代碼
? ? ? ? ? ? if (number>0){
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "賣(mài)出第"+(number--)+"票睹晒,還剩:"+number);
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? lock.unlock(); // 解鎖
? ? ? ? }
? ? }
}
5、synchronized鎖和lock鎖的區(qū)別
1括细、Synchronized 是一個(gè)關(guān)鍵字伪很、Lock 是一個(gè)對(duì)象
2、Synchronized? 無(wú)法嘗試獲取鎖奋单,Lock? 可以嘗試獲取鎖锉试,判斷;
3览濒、Synchronized? 會(huì)自動(dòng)釋放鎖(a線程執(zhí)行完畢呆盖,b如果異常了,也會(huì)釋放鎖)贷笛,lock鎖是手動(dòng)釋放鎖应又!如果你不釋放就會(huì)死鎖。
4乏苦、Synchronized? (線程A(獲得鎖株扛,如果阻塞),線程B(等待汇荐,一直等待)洞就;)lock,可以嘗試獲取鎖拢驾,失敗了之后就放棄
5奖磁、Synchronized 一定是非公平的改基,但是 Lock 鎖可以是公平的繁疤,通過(guò)參數(shù)設(shè)置咖为;
6、代碼量特別大的時(shí)候稠腊,我們一般使用Lock實(shí)現(xiàn)精準(zhǔn)控制躁染,Synchronized? 適合代碼量比較小的同步問(wèn)題;
6架忌、生產(chǎn)者消費(fèi)者
線程和線程之間本來(lái)是不能通信的吞彤,但是有時(shí)候我們需要線程之間可以協(xié)調(diào)操作:
Synchronized 普通版
package com.coding.demo01;
// Synchronized 版
/*
目的: 有兩個(gè)線程:A? B ,還有一個(gè)值初始為0叹放,
? ? ? 實(shí)現(xiàn)兩個(gè)線程交替執(zhí)行饰恕,對(duì)該變量 + 1,-1井仰;交替10次
*/
public class Demo03 {
? ? public static void main(String[] args) {
? ? ? ? Data data = new Data();
? ? ? ? // +1
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <=10 ; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.increment();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? // -1
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <=10 ; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.decrement();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"B").start();
? ? }
}
// 資源類
// 線程之間的通信: 判斷? 執(zhí)行? 通知
class Data{
? ? private int number = 0;
? ? // +1
? ? public synchronized void increment() throws InterruptedException {
? ? ? ? if (number!=0){ // 判斷是否需要等待
? ? ? ? ? ? this.wait();
? ? ? ? }
? ? ? ? number++; // 執(zhí)行
? ? ? ? System.out.println(Thread.currentThread().getName()+"\t"+number);
? ? ? ? // 通知
? ? ? ? this.notifyAll(); //喚醒所有線程
? ? }
? ? // -1
? ? public synchronized void decrement() throws InterruptedException {
? ? ? ? if (number==0){ // 判斷是否需要等待
? ? ? ? ? ? this.wait();
? ? ? ? }
? ? ? ? number--; // 執(zhí)行
? ? ? ? System.out.println(Thread.currentThread().getName()+"\t"+number);
? ? ? ? // 通知
? ? ? ? this.notifyAll(); //喚醒所有線程
? ? }
}
四條線程可以實(shí)現(xiàn)交替嗎埋嵌?不能,會(huì)產(chǎn)生虛假喚醒問(wèn)題俱恶!?
package com.coding.demo01;
// Synchronized 版
/*
目的: 有兩個(gè)線程:A? B 雹嗦,還有一個(gè)值初始為0,
? ? ? 實(shí)現(xiàn)兩個(gè)線程交替執(zhí)行合是,對(duì)該變量 + 1了罪,-1;交替10次
傳統(tǒng)的 wait 和 notify方法不能實(shí)現(xiàn)精準(zhǔn)喚醒通知聪全!
*/
public class Demo03 {
? ? public static void main(String[] args) {
? ? ? ? Data data = new Data();
? ? ? ? // +1
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <=10 ; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.increment();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <=10 ; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.increment();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"C").start();
? ? ? ? // -1
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <=10 ; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.decrement();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"B").start();
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <=10 ; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.decrement();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"D").start();
? ? }
}
// 資源類
// 線程之間的通信: 判斷? 執(zhí)行? 通知
class Data{
? ? private int number = 0;
? ? // +1
? ? public synchronized void increment() throws InterruptedException {
? ? ? ? while (number!=0){ // 判斷是否需要等待
? ? ? ? ? ? this.wait();
? ? ? ? }
? ? ? ? number++; // 執(zhí)行
? ? ? ? System.out.println(Thread.currentThread().getName()+"\t"+number);
? ? ? ? // 通知
? ? ? ? this.notifyAll(); //喚醒所有線程
? ? }
? ? // -1
? ? public synchronized void decrement() throws InterruptedException {
? ? ? ? while (number==0){ // 判斷是否需要等待
? ? ? ? ? ? this.wait();
? ? ? ? }
? ? ? ? number--; // 執(zhí)行
? ? ? ? System.out.println(Thread.currentThread().getName()+"\t"+number);
? ? ? ? // 通知
? ? ? ? this.notifyAll(); //喚醒所有線程
? ? }
}
package com.coding.demo01;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
實(shí)現(xiàn)線程交替執(zhí)行泊藕!
主要的實(shí)現(xiàn)目標(biāo):精準(zhǔn)的喚醒線程!
? ? 三個(gè)線程:A B C
? ? 三個(gè)方法:A p5? B p10? C p15 依次循環(huán)
*/
public class Demo04 {
? ? public static void main(String[] args) {
? ? ? ? Data2 data = new Data2();
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <= 10; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.print5();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <= 10; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.print10();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"B").start();
? ? ? ? new Thread(()->{
? ? ? ? ? ? for (int i = 1; i <= 10; i++) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? data.print15();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? },"C").start();
? ? }
}
// 資源類
class Data2{
? ? private int number = 1; // 1A 2B? 3C
? ? private Lock lock = new ReentrantLock();
? ? // 實(shí)現(xiàn)精準(zhǔn)訪問(wèn)
? ? private Condition condition1 = lock.newCondition();
? ? private Condition condition2 = lock.newCondition();
? ? private Condition condition3 = lock.newCondition();
? ? public void print5() throws InterruptedException {
? ? ? ? lock.lock();
? ? ? ? try {
? ? ? ? ? ? // 判斷
? ? ? ? ? ? while (number!=1){
? ? ? ? ? ? ? ? condition1.await();
? ? ? ? ? ? }
? ? ? ? ? ? // 執(zhí)行
? ? ? ? ? ? for (int i = 1; i <= 5; i++) {
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "\t" + i);
? ? ? ? ? ? }
? ? ? ? ? ? // 通知第二個(gè)線程干活荔烧!
? ? ? ? ? ? number = 2;
? ? ? ? ? ? condition2.signal(); // 喚醒
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? lock.unlock(); // 一定要解鎖
? ? ? ? }
? ? }
? ? public void print10() throws InterruptedException {
? ? ? ? lock.lock();
? ? ? ? try {
? ? ? ? ? ? // 判斷
? ? ? ? ? ? while (number!=2){
? ? ? ? ? ? ? ? condition2.await();
? ? ? ? ? ? }
? ? ? ? ? ? // 執(zhí)行
? ? ? ? ? ? for (int i = 1; i <= 10; i++) {
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "\t" + i);
? ? ? ? ? ? }
? ? ? ? ? ? // 通知3干活
? ? ? ? ? ? number = 3;
? ? ? ? ? ? condition3.signal();
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? lock.unlock();
? ? ? ? }
? ? }
? ? public void print15() throws InterruptedException {
? ? ? ? lock.lock();
? ? ? ? try {
? ? ? ? ? ? // 判斷
? ? ? ? ? ? while (number!=3){
? ? ? ? ? ? ? ? condition3.await();
? ? ? ? ? ? }
? ? ? ? ? ? // 執(zhí)行
? ? ? ? ? ? for (int i = 1; i <= 15; i++) {
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "\t" + i);
? ? ? ? ? ? }
? ? ? ? ? ? // 通知 1 干活
? ? ? ? ? ? number = 1;
? ? ? ? ? ? condition1.signal();
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? lock.unlock();
? ? ? ? }
? ? }
}
7吱七、8道題徹底理解synchronized、static鹤竭、普通方法對(duì)線程鎖的影響
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/*
1踊餐、標(biāo)準(zhǔn)的訪問(wèn)情況下,先執(zhí)行 sendEmail 還是 sendSMS
? 答案:sendEmail
? 被 synchronized 修飾的方式臀稚,鎖的對(duì)象是方法的調(diào)用者吝岭,所以說(shuō)這里兩個(gè)方法調(diào)用的對(duì)象是同一個(gè)
? 先調(diào)用的先執(zhí)行!
*/
public class LockDemo01 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone phone = new Phone();
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone.sendEmail();
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(2);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone.sendSMS();
? ? ? ? },"B").start();
? ? }
}
class Phone{
? ? public synchronized void sendEmail(){
? ? ? ? System.out.println("sendEmail");
? ? }
? ? public synchronized void sendSMS(){
? ? ? ? System.out.println("sendSMS");
? ? }
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/*
2吧寺、sendEmail休眠3秒后 窜管,先執(zhí)行 sendEmail 還是 sendSMS
? 答案:sendEmail
? 被 synchronized 修飾的方式,鎖的對(duì)象是方法的調(diào)用者稚机,所以說(shuō)這里兩個(gè)方法調(diào)用的對(duì)象是同一個(gè)
? 先調(diào)用的先執(zhí)行幕帆!
*/
public class LockDemo02 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone2 phone = new Phone2();
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? phone.sendEmail();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(2);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone.sendSMS();
? ? ? ? },"B").start();
? ? }
}
class Phone2{
? ? public synchronized void sendEmail() throws InterruptedException {
? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? System.out.println("sendEmail");
? ? }
? ? public synchronized void sendSMS(){
? ? ? ? System.out.println("sendSMS");
? ? }
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/*
3、增加一個(gè)普通方法赖条,請(qǐng)問(wèn)先打印那個(gè) sendEmail 還是 hello
? 答案:hello
? 新增加的這個(gè)方法沒(méi)有 synchronized 修飾失乾,不是同步方法常熙,不受鎖的影響!
*/
public class LockDemo03 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone3 phone = new Phone3();
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? phone.sendEmail();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(1);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone.hello();
? ? ? ? },"B").start();
? ? }
}
class Phone3{
? ? public synchronized void sendEmail() throws InterruptedException {
? ? ? ? TimeUnit.SECONDS.sleep(4);
? ? ? ? System.out.println("sendEmail");
? ? }
? ? // 沒(méi)有 synchronized 沒(méi)有 static 就是普通方式
? ? public void hello(){
? ? ? ? System.out.println("hello");
? ? }
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/*
4碱茁、兩個(gè)手機(jī)裸卫,請(qǐng)問(wèn)先執(zhí)行sendEmail 還是 sendSMS
? ? 答案:sendSMS
? ? 被 synchronized? 修飾的方式,鎖的對(duì)象是調(diào)用者纽竣;我們這里有兩個(gè)調(diào)用者墓贿,兩個(gè)方法在這里是兩個(gè)鎖
*/
public class LockDemo04 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone4 phone1 = new Phone4();
? ? ? ? Phone4 phone2 = new Phone4();
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? phone1.sendEmail();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(1);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone2.sendSMS();
? ? ? ? },"B").start();
? ? }
}
class Phone4{
? ? public synchronized void sendEmail() throws InterruptedException {
? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? System.out.println("sendEmail");
? ? }
? ? public synchronized void sendSMS(){
? ? ? ? System.out.println("sendSMS");
? ? }
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
//LockDemo05.Class 模板,只有一個(gè)? ? static
//new LockDemo05(),可以創(chuàng)建多個(gè)對(duì)象
/*
5蜓氨、兩個(gè)靜態(tài)同步方法聋袋,同一個(gè)手機(jī)請(qǐng)問(wèn)先執(zhí)行sendEmail 還是 sendSMS
? ? 答案:sendEmail
? ? 只要方法被 static 修飾,鎖的對(duì)象就是 Class模板對(duì)象,這個(gè)則全局唯一穴吹!所以說(shuō)這里是同一個(gè)鎖
? ? 并不是因?yàn)閟ynchronized
*/
public class LockDemo05 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone5 phone = new Phone5();
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? phone.sendEmail();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(1);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone.sendSMS();
? ? ? ? },"B").start();
? ? }
}
class Phone5{
? ? public static synchronized void sendEmail() throws InterruptedException {
? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? System.out.println("sendEmail");
? ? }
? ? public static synchronized void sendSMS(){
? ? ? ? System.out.println("sendSMS");
? ? }
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
//LockDemo05.Class 模板,只有一個(gè)? ? static
//new LockDemo05()舱馅,可以創(chuàng)建多個(gè)對(duì)象
/*
6、兩個(gè)靜態(tài)同步方法刀荒,兩個(gè)手機(jī)代嗤,請(qǐng)問(wèn)先執(zhí)行sendEmail 還是 sendSMS
? ? 答案:sendEmail
? ? 只要方法被 static 修飾,鎖的對(duì)象就是 Class模板對(duì)象,這個(gè)則全局唯一缠借!所以說(shuō)這里是同一個(gè)鎖
? ? 并不是因?yàn)閟ynchronized
*/
public class LockDemo06 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone6 phone = new Phone6();
? ? ? ? Phone6 phone2 = new Phone6();
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? phone.sendEmail();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(1);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone2.sendSMS();
? ? ? ? },"B").start();
? ? }
}
class Phone6{
? ? public static synchronized void sendEmail() throws InterruptedException {
? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? System.out.println("sendEmail");
? ? }
? ? public static synchronized void sendSMS(){
? ? ? ? System.out.println("sendSMS");
? ? }
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
//LockDemo05.Class 模板,只有一個(gè)? ? static
//new LockDemo05()干毅,可以創(chuàng)建多個(gè)對(duì)象
/*
7、一個(gè)普通同步方法泼返,一個(gè)靜態(tài)同步方法硝逢,只有一個(gè)手機(jī),請(qǐng)問(wèn)先執(zhí)行sendEmail 還是 sendSMS
? ? 答案:sendSMS
? ? synchronized 鎖的是這個(gè)調(diào)用的對(duì)象
? ? static 鎖的是這個(gè)類的Class模板
? ? 這里是兩個(gè)鎖绅喉!
*/
public class LockDemo07 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone7 phone = new Phone7();
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? phone.sendEmail();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(1);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone.sendSMS();
? ? ? ? },"B").start();
? ? }
}
class Phone7{
? ? public static synchronized void sendEmail() throws InterruptedException {
? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? System.out.println("sendEmail");
? ? }
? ? public synchronized void sendSMS(){
? ? ? ? System.out.println("sendSMS");
? ? }
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
//LockDemo05.Class 模板,只有一個(gè)? ? static
//new LockDemo05()渠鸽,可以創(chuàng)建多個(gè)對(duì)象
/*
7、一個(gè)普通同步方法柴罐,一個(gè)靜態(tài)同步方法徽缚,兩個(gè)手機(jī),請(qǐng)問(wèn)先執(zhí)行sendEmail 還是 sendSMS
? ? 答案:sendSMS
? ? synchronized 鎖的是這個(gè)調(diào)用的對(duì)象
? ? static 鎖的是這個(gè)類的Class模板
? ? 這里是兩個(gè)鎖革屠!
*/
public class LockDemo08 {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? Phone8 phone = new Phone8();
? ? ? ? Phone8 phone2 = new Phone8();
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? phone.sendEmail();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? //Thread.sleep(200);
? ? ? ? TimeUnit.SECONDS.sleep(1);
? ? ? ? new Thread(()->{
? ? ? ? ? ? phone2.sendSMS();
? ? ? ? },"B").start();
? ? }
}
class Phone8{
? ? public static synchronized void sendEmail() throws InterruptedException {
? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? System.out.println("sendEmail");
? ? }
? ? public synchronized void sendSMS(){
? ? ? ? System.out.println("sendSMS");
? ? }
}
1凿试、new this 調(diào)用的這個(gè)對(duì)象,是一個(gè)具體的對(duì)象似芝!
2那婉、static? ? ? ? ? class? ? ? 唯一的一個(gè)模板!
在我們編寫(xiě)多線程程序得時(shí)候党瓮,只需要搞明白這個(gè)到底鎖的是什么就不會(huì)出錯(cuò)了详炬!
synchronized(Demo.class){
}
synchronized(this){
}
8、線程不安全的集合類和線程安全的集合類
//list 不安全
package com.coding.unsafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 故障現(xiàn)象:ConcurrentModificationException 并發(fā)修改異常
* 導(dǎo)致原因:add方法沒(méi)有鎖寞奸!
* 解決方案:
* 1呛谜、List<String> list = new Vector<>(); //jdk1.0 就存在的傲醉!效率低
* 2、List<String> list = Collections.synchronizedList(new ArrayList<>());
* 3呻率、List<String> list = new CopyOnWriteArrayList<>();
*
* 什么是 CopyOnWrite; 寫(xiě)入是復(fù)制 (思想 COW)
* 多個(gè)調(diào)用者同時(shí)要相同的資源呻引;這個(gè)有一個(gè)指針的概念礼仗。
* 讀寫(xiě)分離的思想:
*/
public class UnSafeList {
? ? public static void main(String[] args) {
//? ? ? ? List<String> list = Arrays.asList("a", "b", "c");
//? ? ? ? list.forEach(System.out::println);
//? ? ? ? List<String> list = new ArrayList<>();
? ? ? ? List<String> list = new CopyOnWriteArrayList<>();
? ? ? ? for (int i = 1; i <= 30; i++) {
? ? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? ? list.add(UUID.randomUUID().toString().substring(0,3));
? ? ? ? ? ? ? ? System.out.println(list);
? ? ? ? ? ? },String.valueOf(i)).start();
? ? ? ? }
? ? }
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();
? ? }
}
//set 不安全
package com.coding.unsafe;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
// ConcurrentModificationException
public class UnSafeSet {
? ? public static void main(String[] args) {
? ? ? ? // HashSet 底層是什么 就是 HashMap
? ? ? ? // add,就是 HashMap 的 key逻悠;
? ? ? ? Set<String> set = new HashSet<>();
//? ? ? ? Set<String> set = Collections.synchronizedSet(new HashSet<>());
//? ? ? ? Set<String> set = new CopyOnWriteArraySet();
? ? ? ? for (int i = 1; i <=30 ; i++) {
? ? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? ? set.add(UUID.randomUUID().toString().substring(0,3));
? ? ? ? ? ? ? ? System.out.println(set);
? ? ? ? ? ? },String.valueOf(i)).start();
? ? ? ? }
? ? }
}
//map不安全
package com.coding.unsafe;import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
//ConcurrentModificationException
public class UnsafeMap {
? ? public static void main(String[] args) {
? ? ? ? // new HashMap<>() 工作中是這樣用的嗎元践? 不是
? ? ? ? // 加載因子0.75f;,容量 16童谒; 這兩個(gè)值工作中不一定這樣用单旁!
? ? ? ? // 優(yōu)化性能!
? ? ? ? // HashMap 底層數(shù)據(jù)結(jié)構(gòu)饥伊,鏈表 + 紅黑樹(shù)
? ? ? ? // = = = = = = =
//? ? ? ? Map<String, String> map = new HashMap<>();
? ? ? ? Map<String, String> map = new ConcurrentHashMap<>();
? ? ? ? // 人生如程序象浑,不是選擇就是循環(huán),時(shí)常的自我總結(jié)十分重要琅豆!
? ? ? ? for (int i = 1; i <=30 ; i++) {
? ? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? ? map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,3));
? ? ? ? ? ? ? ? System.out.println(map);
? ? ? ? ? ? },String.valueOf(i)).start();
? ? ? ? }
? ? }
}
7愉豺、讀寫(xiě)鎖(了解,使用較少)
package com.coding.rwlock;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
獨(dú)占鎖(寫(xiě)鎖):一次只能被一個(gè)線程占有
共享鎖(讀鎖):該鎖可以被多個(gè)線程占有茫因!
*/
public class ReadWriteLockDemo {
? ? public static void main(String[] args) {
? ? ? ? MyCacheLock myCache = new MyCacheLock();
? ? ? ? // 模擬線程
? ? ? ? // 寫(xiě)
? ? ? ? for (int i = 1; i <= 5; i++) {
? ? ? ? ? ? final int tempInt = i;
? ? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? ? myCache.put(tempInt+"",tempInt+"");
? ? ? ? ? ? },String.valueOf(i)).start();
? ? ? ? }
? ? ? ? // 讀
? ? ? ? for (int i = 1; i <= 5; i++) {
? ? ? ? ? ? final int tempInt = i;
? ? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? ? myCache.get(tempInt+"");
? ? ? ? ? ? },String.valueOf(i)).start();
? ? ? ? }
? ? }
}
// 讀蚪拦、寫(xiě)
class MyCache{
? ? private volatile Map<String,Object> map = new HashMap<>();
? ? // 讀 : 可以被多個(gè)線程同時(shí)讀
? ? public void get(String key){
? ? ? ? System.out.println(Thread.currentThread().getName()+"讀取" + key);
? ? ? ? Object o = map.get(key);
? ? ? ? System.out.println(Thread.currentThread().getName()+"讀取結(jié)果:"+o);
? ? }
? ? // 寫(xiě) :應(yīng)該是保證原子性 , 不應(yīng)該被打擾
? ? public void put(String key,Object value){
? ? ? ? System.out.println(Thread.currentThread().getName()+"寫(xiě)入" + key);
? ? ? ? map.put(key,value);
? ? ? ? System.out.println(Thread.currentThread().getName()+"寫(xiě)入ok" );
? ? }
}
// 加鎖操作: 讀寫(xiě)鎖
class MyCacheLock{
? ? private volatile Map<String,Object> map = new HashMap<>();
? ? // 讀寫(xiě)鎖
? ? private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
? ? // 讀 : 可以被多個(gè)線程同時(shí)讀
? ? public void get(String key){
? ? ? ? // 這些鎖一定要匹配,否則就可能導(dǎo)致死鎖冻押!
? ? ? ? readWriteLock.readLock().lock(); // 多個(gè)線程同時(shí)持有
? ? ? ? try {
? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"讀取" + key);
? ? ? ? ? ? Object o = map.get(key);
? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"讀取結(jié)果:"+o);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? readWriteLock.readLock().unlock();
? ? ? ? }
? ? }
? ? // 寫(xiě) :應(yīng)該是保證原子性 , 不應(yīng)該被打擾
? ? public void put(String key,Object value){
? ? ? ? readWriteLock.writeLock().lock(); // 只能被一個(gè)線程占用
? ? ? ? try {
? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"寫(xiě)入" + key);
? ? ? ? ? ? map.put(key,value);
? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"寫(xiě)入ok" );
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? readWriteLock.writeLock().unlock();
? ? ? ? }
? ? }
}
8驰贷、阻塞隊(duì)列
隊(duì)列 : FIFO ,先進(jìn)先出洛巢,棧:Stack括袒,后進(jìn)先出
阻塞:什么情況下肯定會(huì)阻塞!
1稿茉、當(dāng)隊(duì)列是滿的箱熬,如果繼續(xù)添加元素就會(huì)阻塞
2、當(dāng)隊(duì)列是空的狈邑,如果繼續(xù)取就會(huì)阻塞
如果多線程程序不關(guān)心喚醒城须,就使用阻塞隊(duì)列。
阻塞隊(duì)列是一個(gè)新東西嗎米苹?
List糕伐、Set 這些我們都學(xué)過(guò),其實(shí) BlockingQueue 和 這些是一樣的蘸嘶;
BlockingQueue對(duì)應(yīng)的4組方法
隊(duì)列一般可以檢測(cè)第一個(gè)元素是誰(shuí)良瞧!
package com.coding.queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class BlockingDemo {
? ? public static void main(String[] args) throws InterruptedException {
? ? ? ? // 參數(shù)陪汽,隊(duì)列的大小
? ? ? ? ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
? ? ? ? // java.lang.IllegalStateException: Queue full
? ? ? ? blockingQueue.add("a");
? ? ? ? blockingQueue.add("b");
? ? ? ? blockingQueue.add("c");
? ? ? ? System.out.println(blockingQueue.element());
? ? ? ? //blockingQueue.add("d"); // 報(bào)錯(cuò)、拋棄不報(bào)錯(cuò)褥蚯、一直等待挚冤、超時(shí)等待!
//? ? ? ? System.out.println(blockingQueue.offer("a"));
//? ? ? ? System.out.println(blockingQueue.offer("b"));
//? ? ? ? System.out.println(blockingQueue.offer("c"));
//? ? ? ? System.out.println(blockingQueue.offer("d",3L,TimeUnit.SECONDS)); // 嘗試等待3秒赞庶,就會(huì)失斞档病!返回false
//? ? ? ? blockingQueue.put("a");
//? ? ? ? blockingQueue.put("b");
//? ? ? ? blockingQueue.put("c");
//? ? ? ? System.out.println("準(zhǔn)備放入第四個(gè)元素");
//? ? ? ? blockingQueue.put("d"); // 隊(duì)列滿了歧强,一直等澜薄,并且會(huì)阻塞!
? ? ? ? System.out.println("========================");
? ? ? ? System.out.println(blockingQueue.take());
? ? ? ? System.out.println(blockingQueue.take());
? ? ? ? System.out.println(blockingQueue.take());
? ? ? ? // System.out.println(blockingQueue.take()); // 隊(duì)列空了摊册,一直等肤京,并且會(huì)阻塞!
? ? }
}
同步隊(duì)列
SynchronousQueue 茅特, 只有一個(gè)容量忘分!每一個(gè)put操作,就需要有一個(gè) take操作白修!
package com.coding.queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
// 同步隊(duì)列 : 只能存放一個(gè)值饭庞!
public class SynchronousQueueDemo {
? ? public static void main(String[] args) {
? ? ? ? // 特殊的阻塞隊(duì)列
? ? ? ? BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
? ? ? ? // A 存
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "put a");
? ? ? ? ? ? ? ? blockingQueue.put("a");
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "put b");
? ? ? ? ? ? ? ? blockingQueue.put("b");
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "put c");
? ? ? ? ? ? ? ? blockingQueue.put("c");
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? ? ? // B 取
? ? ? ? new Thread(()->{
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + blockingQueue.take());
? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + blockingQueue.take());
? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(3);
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + blockingQueue.take());
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? },"A").start();
? ? }
}
9、線程池
池化技術(shù):程序運(yùn)行的本質(zhì):占用系統(tǒng)資源熬荆! 提高程序的使用率舟山,降低我們一個(gè)性能消耗
線程池、連接池卤恳、內(nèi)存池累盗、對(duì)象池 ............
為什么要用線程池:線程復(fù)用
關(guān)于我們的線程池
三大方法、七大參數(shù)突琳、4種拒絕策略
三大方法:
package com.coding.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo01 {
? ? public static void main(String[] args) {
? ? ? ? // 單例若债,只能有一個(gè)線程!
//? ? ? ? ExecutorService threadPool = Executors.newSingleThreadExecutor();
? ? ? ? // 固定的線程數(shù)
//? ? ? ? ExecutorService threadPool = Executors.newFixedThreadPool(8);
? ? ? ? // 遇強(qiáng)則強(qiáng)拆融!可伸縮蠢琳!
//? ? ? ? ExecutorService threadPool = Executors.newCachedThreadPool();
? ? ? ? try {
? ? ? ? ? ? // 線程池的使用方式!
? ? ? ? ? ? for (int i = 0; i < 30; i++) {
? ? ? ? ? ? ? ? threadPool.execute(()->{
? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + " ok");
? ? ? ? ? ? ? ? });
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? // 使用完畢后需要關(guān)閉镜豹!
? ? ? ? ? ? threadPool.shutdown();
? ? ? ? }
? ? }
}
七大參數(shù)
1傲须、先看看這個(gè)三個(gè)方法的源碼
new ThreadPoolExecutor(0, Integer.MAX_VALUE, // 約等于21億
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 60L, TimeUnit.SECONDS,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new SynchronousQueue<Runnable>());
new ThreadPoolExecutor(nThreads, nThreads,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0L, TimeUnit.MILLISECONDS,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new LinkedBlockingQueue<Runnable>());
ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new LinkedBlockingQueue<Runnable>())
public ThreadPoolExecutor(int corePoolSize, // 核心池線程數(shù)大小 (常用)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int maximumPoolSize,? // 最大的線程數(shù)大小 (常用)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? long keepAliveTime, // 超時(shí)等待時(shí)間 (常用)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TimeUnit unit, // 時(shí)間單位 (常用)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BlockingQueue<Runnable> workQueue, // 阻塞隊(duì)列(常用)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ThreadFactory threadFactory, // 線程工廠
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RejectedExecutionHandler handler // 拒絕策略(常用)) {
? ? if (corePoolSize < 0 ||
? ? ? ? maximumPoolSize <= 0 ||
? ? ? ? maximumPoolSize < corePoolSize ||
? ? ? ? keepAliveTime < 0)
? ? ? ? throw new IllegalArgumentException();
? ? if (workQueue == null || threadFactory == null || handler == null)
? ? ? ? throw new NullPointerException();
? ? this.acc = System.getSecurityManager() == null ?
? ? ? ? null :
? ? AccessController.getContext();
? ? this.corePoolSize = corePoolSize;
? ? this.maximumPoolSize = maximumPoolSize;
? ? this.workQueue = workQueue;
? ? this.keepAliveTime = unit.toNanos(keepAliveTime);
? ? this.threadFactory = threadFactory;
? ? this.handler = handler;
}
自定義線程池的策略
package com.coding.pool;
import java.util.concurrent.*;
public class ThreadPoolDemo01 {
? ? public static void main(String[] args) {
? ? ? ? // 單例,只能有一個(gè)線程趟脂!
//? ? ? ? ExecutorService threadPool = Executors.newSingleThreadExecutor();
? ? ? ? // 固定的線程數(shù)
//? ? ? ? ExecutorService threadPool = Executors.newFixedThreadPool(1);
? ? ? ? //遇強(qiáng)則強(qiáng)泰讽!可伸縮!
//? ? ? ? ExecutorService threadPool = Executors.newCachedThreadPool();
? ? ? ? ExecutorService threadPool = new ThreadPoolExecutor(
? ? ? ? ? ? ? ? 2,
? ? ? ? ? ? ? ? 5,
? ? ? ? ? ? ? ? 3L,
? ? ? ? ? ? ? ? TimeUnit.SECONDS,
? ? ? ? ? ? ? ? new LinkedBlockingDeque<>(3),
? ? ? ? ? ? ? ? Executors.defaultThreadFactory(),
? ? ? ? ? ? ? ? new ThreadPoolExecutor.CallerRunsPolicy());
? ? ? ? try {
? ? ? ? ? ? // 線程池的使用方式!
? ? ? ? ? ? for (int i = 0; i < 100; i++) {
? ? ? ? ? ? ? ? threadPool.execute(()->{
? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + " ok");
? ? ? ? ? ? ? ? });
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } finally {
? ? ? ? ? ? // 使用完畢后需要關(guān)閉已卸!
? ? ? ? ? ? threadPool.shutdown();
? ? ? ? }
? ? }
}
四大拒絕策略
/**
? ? ? ? * 1佛玄、ThreadPoolExecutor.AbortPolicy();? 拋出異常累澡,丟棄任務(wù)
? ? ? ? * 思路:看到效果一樣的東西梦抢,可以研究研究!
? ? ? ? * 2愧哟、ThreadPoolExecutor.DiscardPolicy()奥吩;不拋出異常,丟棄任務(wù)
? ? ? ? * 3翅雏、ThreadPoolExecutor.DiscardOldestPolicy(); 嘗試獲取任務(wù)人芽,不一定執(zhí)行望几!
? ? ? ? * 4、ThreadPoolExecutor.CallerRunsPolicy()萤厅; 哪來(lái)的去哪里找對(duì)應(yīng)的線程執(zhí)行橄抹!
? ? ? ? */
請(qǐng)你談?wù)?最大線程池 該如何設(shè)置啊惕味?
CPU密集型: 根據(jù)CPU的處理器數(shù)量來(lái)定楼誓!保證最大效率
IO密集型: 50 個(gè)線程都是進(jìn)程操作大io資源, 比較耗時(shí)! > 這個(gè)常用的 IO 任務(wù)數(shù)名挥!
10疟羹、四個(gè)函數(shù)式接口
java.util.function
所有的函數(shù)式接口都可以用來(lái)簡(jiǎn)化編程模型: 都可以使用lambda表達(dá)式簡(jiǎn)化!
/**
* 函數(shù)式接口是我們現(xiàn)在必須要要掌握且精通的
* 4個(gè)禀倔!
* Java 8
*
* Function : 有一個(gè)輸入?yún)?shù)有一個(gè)輸出參數(shù)
* Consumer:有一個(gè)輸入?yún)?shù)榄融,沒(méi)有輸出參數(shù)
* Supplier:沒(méi)有輸入?yún)?shù),只有輸出參數(shù)
* Predicate:有一個(gè)輸入?yún)?shù)救湖,判斷是否正確愧杯!
*/
package com.coding.funcation;
import java.util.function.Function;
/**
* 函數(shù)式接口是我們現(xiàn)在必須要要掌握且精通的
* 4個(gè)!
* Java 8
*
* Function : 有一個(gè)輸入?yún)?shù)有一個(gè)輸出參數(shù)
* Consumer:有一個(gè)輸入?yún)?shù)鞋既,沒(méi)有輸出參數(shù)
* Supplier:沒(méi)有輸入?yún)?shù)力九,只有輸出參數(shù)
* Predicate:有一個(gè)輸入?yún)?shù),判斷是否正確邑闺!
*/
public class Demo01 {
? ? public static void main(String[] args) {
? ? ? ? //
//? ? ? ? Function<String,Integer> function = new Function<String,Integer>() {
//? ? ? ? ? ? @Override
//? ? ? ? ? ? public Integer apply(String str) {
//? ? ? ? ? ? ? ? return str.length();
//? ? ? ? ? ? }
//? ? ? ? };
? ? ? ? // (參數(shù))->{方法體}
? ? ? ? Function<String,Integer> function = (str)->{return str.length();};
? ? ? ? System.out.println(function.apply("a45645646"));
? ? }
}
package com.coding.funcation;
import java.util.function.Predicate;
// Predicate
public class Demo02 {
? ? public static void main(String[] args) {
//? ? ? ? Predicate<String> predicate = new Predicate<String>() {
//? ? ? ? ? ? @Override
//? ? ? ? ? ? public boolean test(String str) {
//? ? ? ? ? ? ? ? return str.isEmpty();
//? ? ? ? ? ? }
//? ? ? ? };
? ? ? ? Predicate<String> predicate = str->{return str.isEmpty();};
? ? ? ? System.out.println(predicate.test("456"));
? ? }
}
package com.coding.funcation;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class Demo03 {
? ? public static void main(String[] args) {
//? ? ? ? Supplier<String> supplier = new Supplier<String>() {
//? ? ? ? ? ? // 語(yǔ)法糖
//? ? ? ? ? ? @Override
//? ? ? ? ? ? public String get() {
//? ? ? ? ? ? ? ? return "《hello跌前,spring》";
//? ? ? ? ? ? }
//? ? ? ? };
? ? ? ? Supplier<String> supplier = ()->{return "《hello,spring》";};
? ? ? ? Consumer<String> consumer = s->{ System.out.println(s);};
//? ? ? ? Consumer<String> consumer = new Consumer<String>() {
//? ? ? ? ? ? @Override
//? ? ? ? ? ? public void accept(String s) {
//? ? ? ? ? ? ? ? System.out.println(s);
//? ? ? ? ? ? }
//? ? ? ? };
? ? ? ? consumer.accept(supplier.get());
? ? }
}
11陡舅、Stream流式計(jì)算
package com.coding.stream;
import java.util.Arrays;
import java.util.List;
// 數(shù)據(jù)庫(kù)舒萎、集合 : 存數(shù)據(jù)的
// Stream:計(jì)算和處理數(shù)據(jù)交給 Stream
public class StreamDemo {
? ? /**
? ? * 按條件用戶篩選:
? ? * 1、id 為偶數(shù)
? ? * 2、年齡大于24
? ? * 3臂寝、用戶名大寫(xiě)? 映射
? ? * 4章鲤、用戶名倒排序
? ? * 5、輸出一個(gè)用戶
? ? *
? ? * 請(qǐng)你只用一行代碼完成咆贬!
? ? */
? ? public static void main(String[] args) {
? ? ? ? User u1 = new User(1,"a",23);
? ? ? ? User u2 = new User(2,"b",24);
? ? ? ? User u3 = new User(3,"c",22);
? ? ? ? User u4 = new User(4,"d",28);
? ? ? ? User u5 = new User(6,"e",26);
? ? ? ? // 存儲(chǔ)
? ? ? ? List<User> users = Arrays.asList(u1, u2, u3, u4, u5);
? ? ? ? // 計(jì)算等操作交給流
? ? ? ? // forEach(消費(fèi)者類型接口)
? ? ? ? users.stream()
? ? ? ? ? ? ? ? .filter(u->{return u.getId()%2==0;})
? ? ? ? ? ? ? ? .filter(u->{return u.getAge()>24;})
? ? ? ? ? ? ? ? .map(u->{return u.getName().toUpperCase();})
? ? ? ? ? ? ? ? .sorted((o1,o2)->{return o2.compareTo(o1);})
? ? ? ? ? ? ? ? .limit(1)
? ? ? ? ? ? ? ? .forEach(System.out::println);
? ? ? ? // 在JDK1.5 的時(shí)候败徊,枚舉:反射、注解掏缎、泛型
? ? ? ? // 在JDK1.8 的時(shí)候? 函數(shù)式接口皱蹦、Stream流式計(jì)算、lambda表達(dá)式眷蜈、鏈?zhǔn)骄幊蹋?/p>
? ? ? ? // 無(wú)論何時(shí)沪哺,都還需要掌握一個(gè)東西叫 JVM;
? ? ? ? // JVM: 你會(huì)了這個(gè)技術(shù)不會(huì)覺(jué)得你恨厲害酌儒!
? ? }
}
12辜妓、分支合并
什么是 forkjoin
MapReduce:input->split->map->reduce->output
主要就是兩步:
1、任務(wù)拆分
2忌怎、結(jié)果合并
前提:forkjoin 一定是用在大數(shù)據(jù)量的情況下
工作原理:工作竊取? 底層維護(hù)的是一個(gè)雙端隊(duì)列籍滴;
好處:效率高
壞處:產(chǎn)生資源爭(zhēng)奪
13、異步回調(diào)
Future
CompletableFuture
package com.coding.future;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class CompletableFutureDemo {
? ? public static void main(String[] args) throws ExecutionException, InterruptedException {
? ? ? ? // 沒(méi)有返回值,好比多線程榴啸,功能更強(qiáng)大孽惰!
//? ? ? ? CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
//? ? ? ? ? ? try {
//? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(2);
//? ? ? ? ? ? } catch (InterruptedException e) {
//? ? ? ? ? ? ? ? e.printStackTrace();
//? ? ? ? ? ? }
//? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "沒(méi)有返回值!");
//? ? ? ? });
//? ? ? ? System.out.println("111111");
//? ? ? ? completableFuture.get();
? ? ? ? // 有返回值
? ? ? ? // 任務(wù)
? ? ? ? CompletableFuture<Integer> uCompletableFuture = CompletableFuture.supplyAsync(() -> {
? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"=>supplyAsync!");
? ? ? ? ? ? int i = 10/0;
? ? ? ? ? ? return 1024;
? ? ? ? });
? ? ? ? System.out.println(uCompletableFuture.whenComplete((t, u) -> { // 成功
? ? ? ? ? ? System.out.println("t=>" + t); // 正確結(jié)果
? ? ? ? ? ? System.out.println("u=>" + u); // 錯(cuò)誤信息
? ? ? ? }).exceptionally(e -> { // 失敗鸥印,如果錯(cuò)誤就返回錯(cuò)誤的結(jié)果勋功!
? ? ? ? ? ? System.out.println("e:" + e.getMessage());
? ? ? ? ? ? return 500;
? ? ? ? }).get());
? ? }
}