JUC并發(fā)編程

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());

? ? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市库说,隨后出現(xiàn)的幾起案子酝润,更是在濱河造成了極大的恐慌,老刑警劉巖璃弄,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件要销,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡夏块,警方通過(guò)查閱死者的電腦和手機(jī)疏咐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脐供,“玉大人浑塞,你說(shuō)我怎么就攤上這事≌海” “怎么了酌壕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我卵牍,道長(zhǎng)果港,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任糊昙,我火速辦了婚禮辛掠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘释牺。我一直安慰自己萝衩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布没咙。 她就那樣靜靜地躺著猩谊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祭刚。 梳的紋絲不亂的頭發(fā)上牌捷,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音袁梗,去河邊找鬼宜鸯。 笑死憔古,一個(gè)胖子當(dāng)著我的面吹牛遮怜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸿市,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼锯梁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了焰情?” 一聲冷哼從身側(cè)響起陌凳,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎内舟,沒(méi)想到半個(gè)月后合敦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡验游,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年充岛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耕蝉。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡崔梗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出垒在,到底是詐尸還是另有隱情蒜魄,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站谈为,受9級(jí)特大地震影響旅挤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜峦阁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一谦铃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧榔昔,春花似錦驹闰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至诵肛,卻和暖如春屹培,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背怔檩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工褪秀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人薛训。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓媒吗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親乙埃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闸英,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容