欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報邀請碼778899分享:Java之線程篇七

柚子快報邀請碼778899分享:Java之線程篇七

http://yzkb.51969.com/

目錄

單例模式

餓漢模式

懶漢模式-單線程版

懶漢模式-多線程版

阻塞隊列

生產(chǎn)者消費(fèi)者模型

標(biāo)準(zhǔn)庫中的阻塞隊列

阻塞隊列實現(xiàn)

定時器

標(biāo)準(zhǔn)庫中的定時器

實現(xiàn)定時器

線程池

標(biāo)準(zhǔn)庫中的線程池

Executors 創(chuàng)建線程池的幾種方式

線程池的優(yōu)點(diǎn)

ThreadPoolExecutor的構(gòu)造方法

單例模式

單例模式能保證某個類在程序中只存在唯一一份實例, 而不會創(chuàng)建出多個實例. 單例模式具體的實現(xiàn)方式, 分成 "餓漢" 和 "懶漢" 兩種.

餓漢模式

類加載的同時

,

創(chuàng)建實例

.

代碼示例

// 期望這個類能夠有唯一一個實例.

class Singleton {

private static Singleton instance = new Singleton();

// 通過這個方法來獲取到剛才的實例.

// 后續(xù)如果想使用這個類的實例, 都通過 getInstance 方法來獲取.

public static Singleton getInstance() {

return instance;

}

// 把構(gòu)造方法設(shè)置為 私有 . 此時類外面的其他代碼, 就無法 new 出這個類的對象了.

private Singleton() { }

}

public class Demo17 {

public static void main(String[] args) {

Singleton s1 = Singleton.getInstance();

Singleton s2 = Singleton.getInstance();

System.out.println(s1 == s2);

}

}

運(yùn)行結(jié)果

懶漢模式-單線程版

類加載的時候不創(chuàng)建實例

.

第一次使用的時候才創(chuàng)建實例

.

class Singleton {

? ?private static Singleton instance = null;

? ?private Singleton() {}

? ?public static Singleton getInstance() {

? ? ? ?if (instance == null) {

? ? ? ? ? ?instance = new Singleton();

? ? ? }

? ? ? ?return instance;

? }

}

懶漢模式-多線程版

class Singleton {

? ?private static Singleton instance = null;

? ?private Singleton() {}

? ?public synchronized static Singleton getInstance() {

? ? ? ?if (instance == null) {

? ? ? ? ? ?instance = new Singleton();

? ? ? }

? ? ? ?return instance;

? }

}

懶漢模式-多線程版改進(jìn)

使用雙重

if

判定

,

降低鎖競爭的頻率

.

instance

加上了

volatile.

class Singleton {

? ?private static volatile Singleton instance = null;

? ?private Singleton() {}

? ?public static Singleton getInstance() {

? ? ? ?if (instance == null) {

? ? ? ? ? ?synchronized (Singleton.class) {

? ? ? ? ? if (instance == null) {

? ? ? ? ? ? ? instance = new Singleton();

? ? ? ? ? ? ? }

? ? ? ? ? }

? ? ? }

? ? ? ?return instance;

? }

}

上述代碼使用volatile的作用

1.防止指令重排序:在多線程環(huán)境中,JVM 和現(xiàn)代處理器可能會對代碼進(jìn)行優(yōu)化,以提高執(zhí)行效率。這種優(yōu)化可能包括指令重排序,即改變指令的執(zhí)行順序。在 Singleton 的實例化過程中,如果 instance 變量沒有被聲明為 volatile,那么 JVM 可能會將 instance = new Singleton(); 這行代碼分解為三個操作:分配內(nèi)存給 instance。 調(diào)用 Singleton 的構(gòu)造函數(shù)來初始化對象。 將 instance 指向分配的內(nèi)存地址。 如果沒有 volatile,這三個操作可能會被重排序,導(dǎo)致某個線程在 instance 被正確初始化之前就觀察到 instance 不為 null 的情況,但此時 instance 指向的對象可能還沒有完全初始化(即構(gòu)造函數(shù)還未完全執(zhí)行完畢)。這被稱為“部分初始化”問題,可能導(dǎo)致程序出現(xiàn)不可預(yù)測的行為。通過聲明 instance 為 volatile,JVM 會保證 instance 的賦值操作不會被重排序到構(gòu)造函數(shù)調(diào)用之前,從而避免這個問題。

2.保證可見性:volatile 關(guān)鍵字還確保了不同線程之間對 instance 變量的可見性。即,當(dāng)一個線程修改了 instance 的值(從 null 變?yōu)橹赶蛞粋€ Singleton 實例的引用),這個修改會立即對其他線程可見。沒有 volatile,一個線程可能無法看到另一個線程對 instance 的修改,從而導(dǎo)致它錯誤地創(chuàng)建另一個 Singleton 實例。

阻塞隊列

阻塞隊列是一種特殊的隊列. 也遵守 "先進(jìn)先出" 的原則.?

阻塞隊列能是一種線程安全的數(shù)據(jù)結(jié)構(gòu), 并且具有以下特性:

當(dāng)隊列滿的時候, 繼續(xù)入隊列就會阻塞, 直到有其他線程從隊列中取走元素.?

當(dāng)隊列空的時候, 繼續(xù)出隊列也會阻塞, 直到有其他線程往隊列中插入元素.?

阻塞隊列的一個典型應(yīng)用場景就是 "生產(chǎn)者消費(fèi)者模型". 這是一種非常典型的開發(fā)模型.?

生產(chǎn)者消費(fèi)者模型

生產(chǎn)者消費(fèi)者模式就是通過一個容器來解決生產(chǎn)者和消費(fèi)者的強(qiáng)耦合問題。 生產(chǎn)者和消費(fèi)者彼此之間不直接通訊,而通過阻塞隊列來進(jìn)行通訊,所以生產(chǎn)者生產(chǎn)完數(shù)據(jù)之后不用等待消費(fèi)者處理,直接扔給阻塞隊列,消費(fèi)者不找生產(chǎn)者要數(shù)據(jù),而是直接從阻塞隊列里取.?

1) 阻塞隊列就相當(dāng)于一個緩沖區(qū),平衡了生產(chǎn)者和消費(fèi)者的處理能力. 2) 阻塞隊列也能使生產(chǎn)者和消費(fèi)者之間 解耦.

標(biāo)準(zhǔn)庫中的阻塞隊列

Java

標(biāo)準(zhǔn)庫中內(nèi)置了阻塞隊列

.

如果我們需要在一些程序中使用阻塞隊列

,

直接使用標(biāo)準(zhǔn)庫中的即可

.

BlockingQueue

是一個接口

.

真正實現(xiàn)的類是

LinkedBlockingQueue.

put

方法用于阻塞式的入隊列

, take

用于阻塞式的出隊列

.

BlockingQueue

也有

offer, poll, peek

等方法

,

但是這些方法不帶有阻塞特性

.

?代碼示例

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.LinkedBlockingQueue;

public class Demo19 {

public static void main(String[] args) throws InterruptedException {

BlockingQueue queue = new LinkedBlockingQueue<>();

queue.put("111");

queue.put("222");

queue.put("333");

queue.put("444");

String elem = queue.take();

System.out.println(elem);

elem = queue.take();

System.out.println(elem);

elem = queue.take();

System.out.println(elem);

elem = queue.take();

System.out.println(elem);

elem = queue.take();

System.out.println(elem);

}

}

運(yùn)行結(jié)果

阻塞隊列實現(xiàn)

通過 "循環(huán)隊列" 的方式來實現(xiàn).? 使用 synchronized 進(jìn)行加鎖控制.? put 插入元素的時候, 判定如果隊列滿了, 就進(jìn)行 wait. (注意, 要在循環(huán)中進(jìn)行 wait. 被喚醒時不一定隊列就不滿了, 因為同時可能是喚醒了多個線程).? take 取出元素的時候, 判定如果隊列為空, 就進(jìn)行 wait.

class MyBlockingQueue{

private String[] data=new String[1000];

private volatile int head=0;//隊列起始位置

private volatile int tail = 0;//隊列結(jié)束位置的下一個位置

private volatile int size=0;//隊列中有效元素的個數(shù)

public void put(String elem) throws InterruptedException {

synchronized (this){

while(size==data.length){

this.wait();

}

data[tail]=elem;

tail++;

if(tail==data.length)

tail=0;

size++;

this.notify();

}

}

public String take() throws InterruptedException {

synchronized (this){

while(size==0){

this.wait();

}

String ret=data[head];

head++;

if(head== data.length)

head=0;

size--;

this.notify();

return ret;

}

}

}

public class Demo18 {

public static void main(String[] args) {

MyBlockingQueue queue=new MyBlockingQueue();

//消費(fèi)者

Thread t1=new Thread(()->{

while(true){

try {

String result=queue.take();

System.out.println("消費(fèi)元素:"+result);

Thread.sleep(1000);

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

});

//生產(chǎn)者

Thread t2=new Thread(()->{

int num=1;

while(true){

try {

queue.put(num+"");

System.out.println("生產(chǎn)元素:"+num);

num++;

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

});

t1.start();

t2.start();

}

}

?運(yùn)行結(jié)果

定時器

定時器也是軟件開發(fā)中的一個重要組件

.

類似于一個

"

鬧鐘

".

達(dá)到一個設(shè)定的時間之后

,

就執(zhí)行某個指定好的代碼.

標(biāo)準(zhǔn)庫中的定時器

標(biāo)準(zhǔn)庫中提供了一個

Timer

. Timer

類的核心方法為

schedule

.

schedule

包含兩個參數(shù)

.

第一個參數(shù)指定即將要執(zhí)行的任務(wù)代碼

,

第二個參數(shù)指定多長時間之后執(zhí)行 (

單位為毫秒

).

代碼示例

import java.util.Timer;

import java.util.TimerTask;

public class Demo20 {

public static void main(String[] args) {

Timer timer=new Timer();

//給定時器安排一個任務(wù),預(yù)定在某個時間去執(zhí)行

timer.schedule(new TimerTask() {

@Override

public void run() {

System.out.println("3000");

}

},3000);

timer.schedule(new TimerTask() {

@Override

public void run() {

System.out.println("2000");

}

},2000);

timer.schedule(new TimerTask() {

@Override

public void run() {

System.out.println("1000");

}

},1000);

System.out.println("程序啟動");

}

}

運(yùn)行結(jié)果

實現(xiàn)定時器

定時器的構(gòu)成:

1.一個帶優(yōu)先級的阻塞隊列

為啥要帶優(yōu)先級呢??

因為阻塞隊列中的任務(wù)都有各自的執(zhí)行時刻 (delay). 最先執(zhí)行的任務(wù)一定是 delay 最小的. 使用帶

優(yōu)先級的隊列就可以高效的把這個 delay 最小的任務(wù)找出來.?

2.隊列中的每個元素是一個 Task 對象.

3.Task 中帶有一個時間屬性, 隊首元素就是即將要執(zhí)行的任務(wù).

4.同時有一個 worker 線程一直掃描隊首元素, 看隊首元素是否需要執(zhí)行

代碼示例

import java.util.Comparator;

import java.util.PriorityQueue;

import java.util.TimerTask;

class MyTimerTask implements Comparable{

private Runnable runnable;

private long time;

public MyTimerTask(Runnable runnable,long delay){

this.runnable=runnable;

this.time=System.currentTimeMillis()+delay;

}

@Override

public int compareTo(MyTimerTask o) {

return (int)(this.time-o.time);

}

public long getTime(){

return time;

}

public Runnable getRunnable() {

return runnable;

}

}

class MyTimer{

private PriorityQueue queue=new PriorityQueue<>();

private Object locker=new Object();

public void schedule(Runnable runnable,long delay){

synchronized (locker){

queue.offer(new MyTimerTask(runnable,delay));

locker.notify();

}

}

public MyTimer() {

Thread t=new Thread(()->{

while(true) {

try {

synchronized (locker) {

while (queue.isEmpty()) {

locker.wait();

}

MyTimerTask task = queue.peek();

long curTime = System.currentTimeMillis();

if (curTime >= task.getTime()) {

task.getRunnable().run();

queue.poll();

} else {

locker.wait(task.getTime() - curTime);

}

}

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

});

t.start();

}

}

public class Demo21 {

public static void main(String[] args) {

MyTimer timer = new MyTimer();

timer.schedule(new Runnable() {

@Override

public void run() {

System.out.println("3000");

}

}, 3000);

timer.schedule(new Runnable() {

@Override

public void run() {

System.out.println("2000");

}

}, 2000);

timer.schedule(new Runnable() {

@Override

public void run() {

System.out.println("1000");

}

}, 1000);

System.out.println("程序開始執(zhí)行");

}

}

線程池

線程池最大的好處就是減少每次啟動、銷毀線程的損耗。

標(biāo)準(zhǔn)庫中的線程池

使用 Executors.newFixedThreadPool(4) 能創(chuàng)建出固定包含 4?個線程的線程池.?

返回值類型為 ExecutorService

通過 ExecutorService.submit 可以注冊一個任務(wù)到線程池中.

代碼示例

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Demo22 {

public static void main(String[] args) {

ExecutorService service= Executors.newFixedThreadPool(4);

service.submit(new Runnable() {

@Override

public void run() {

System.out.println("hello");

}

});

}

}

?運(yùn)行結(jié)果

Executors 創(chuàng)建線程池的幾種方式

newFixedThreadPool: 創(chuàng)建固定線程數(shù)的線程池 newCachedThreadPool: 創(chuàng)建線程數(shù)目動態(tài)增長的線程池. newSingleThreadExecutor: 創(chuàng)建只包含單個線程的線程池.? newScheduledThreadPool: 設(shè)定 延遲時間后執(zhí)行命令,或者定期執(zhí)行命令. 是進(jìn)階版的 Timer.?

Executors 本質(zhì)上是 ThreadPoolExecutor 類的封裝.?

實現(xiàn)線程池

import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;

class MyThreadPool{

private BlockingQueue queue=new ArrayBlockingQueue<>(1000);

public void submit(Runnable runnable) throws InterruptedException {

queue.put(runnable);

}

public MyThreadPool(int n){

for (int i = 0; i < n; i++) {

Thread t=new Thread(()->{

Runnable runnable= null;

try {

runnable = queue.take();

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

runnable.run();

});

t.start();

}

}

}

public class Demo23 {

public static void main(String[] args) throws InterruptedException {

MyThreadPool myThreadPool=new MyThreadPool(4);

for (int i = 0; i < 1000; i++) {

int id=i;

myThreadPool.submit(new Runnable() {

@Override

public void run() {

System.out.println("執(zhí)行任務(wù):"+id);

}

});

}

}

}

運(yùn)行結(jié)果

線程池的優(yōu)點(diǎn)

1.減少資源消耗:通過重用已存在的線程,線程池避免了線程創(chuàng)建和銷毀所帶來的開銷。線程創(chuàng)建和銷毀是昂貴的操作,因為它們涉及到系統(tǒng)資源的分配和釋放。使用線程池可以顯著減少這些開銷,提高系統(tǒng)的資源利用率。 2.提高響應(yīng)速度:由于線程池中的線程是預(yù)先創(chuàng)建好的,當(dāng)有新任務(wù)到來時,可以立即分配線程去執(zhí)行,而不需要等待新線程的創(chuàng)建。這可以顯著提高系統(tǒng)的響應(yīng)速度,尤其是在高并發(fā)場景下。 3.提高線程的可管理性:線程池提供了一種集中管理線程的方式,包括線程的創(chuàng)建、銷毀、調(diào)度等。通過線程池,開發(fā)者可以更容易地控制系統(tǒng)中線程的數(shù)量,避免創(chuàng)建過多的線程導(dǎo)致系統(tǒng)資源耗盡。 4.提供靈活的配置選項:大多數(shù)線程池實現(xiàn)都提供了豐富的配置選項,如線程池的大小、任務(wù)的隊列類型、拒絕策略等。這些配置選項使得開發(fā)者可以根據(jù)應(yīng)用程序的具體需求來優(yōu)化線程池的性能。 5.簡化并發(fā)編程:線程池隱藏了線程管理的復(fù)雜性,使得開發(fā)者可以更加專注于業(yè)務(wù)邏輯的實現(xiàn),而不是線程的管理。這簡化了并發(fā)編程的難度,降低了出錯的可能性。 6.支持并發(fā)任務(wù)的執(zhí)行:線程池可以同時執(zhí)行多個任務(wù),提高了系統(tǒng)的并發(fā)處理能力。這對于需要處理大量并發(fā)請求的應(yīng)用程序來說是非常重要的。 7.提供任務(wù)調(diào)度功能:一些高級的線程池實現(xiàn)還提供了任務(wù)調(diào)度的功能,允許開發(fā)者按照特定的策略(如定時、周期性等)來執(zhí)行任務(wù)。這進(jìn)一步增強(qiáng)了線程池的靈活性和功能。

ThreadPoolExecutor的構(gòu)造方法

?上圖中最后一個構(gòu)造函數(shù)功能最多,以這個為介紹對象:

corePoolSize:核心線程數(shù)

maximumPoolSize:最大線程數(shù)

線程池里面的線程數(shù)目:[corePoolSize,maximumPoolSize]

keepAlive:允許線程最大的存活時間

unit:時間單位

workQueue:阻塞隊列,用來存放線程池中的任務(wù)

threadFactory:工廠模式

handler:拒絕策略

柚子快報邀請碼778899分享:Java之線程篇七

http://yzkb.51969.com/

精彩文章

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://m.gantiao.com.cn/post/19580072.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄