Java多線程?一篇就夠了
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
一.認(rèn)識(shí)線程及線程的創(chuàng)建
1.線程的概念
2.線程的特性
3.線程的創(chuàng)建方式
<1>繼承Thread類
class MyThread extends Thread{
@Override
public void run() {
System.out.println("繼承Thread類創(chuàng)建線程");
}
}
public static void main(String[] args) {
//1.繼承Thread類創(chuàng)建線程
MyThread t=new MyThread();
t.start();
}
<2>實(shí)現(xiàn)Runnable接口
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("繼承Runnable接口,創(chuàng)建描述任務(wù)對(duì)象,實(shí)現(xiàn)多線程");
}
}
public static void main(String[] args) {
//2.實(shí)現(xiàn)Runnable接口
Thread t1=new Thread(new MyRunnable());
t1.start();
}
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("使用Runnable接口,創(chuàng)建匿名內(nèi)部類實(shí)現(xiàn)");
}
});
t2.start();
<3>實(shí)現(xiàn)Callable接口
class MyCallable implements Callable<String> {
//允許拋出異常,允許帶有返回值,返回?cái)?shù)據(jù)類型為接口上的泛型
@Override
public String call() throws Exception {
System.out.println("實(shí)現(xiàn)了Callable接口");
return "這不是一個(gè)線程類,而是一個(gè)任務(wù)類";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//方法三:實(shí)現(xiàn)Callable接口,是一個(gè)任務(wù)類
//FutureTask底層也實(shí)現(xiàn)了Runnable接口
FutureTask<String> task=new FutureTask<>(new MyCallable());
new Thread(task).start();
System.out.println(task.get());
}
二.線程的常用方法
1.構(gòu)造方法和屬性的獲取方法
2.常用方法
<1>run()和start()
public class Thread_Run_VS_Start {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while (true){
}
}
}).run();
/**
* main線程直接調(diào)用Thread對(duì)象的run方法會(huì)直接在main線程
* 運(yùn)行Thread對(duì)象的run()方法---->傳入的runnable對(duì)象.run()
* 結(jié)果,main線程直接運(yùn)行while(true)
*
* start()是啟動(dòng)一個(gè)線程,調(diào)用新線程的while(true)方法
* 對(duì)比通過(guò)start()調(diào)用的結(jié)果區(qū)別
*/
new Thread(new Runnable() {
@Override
public void run() {
while (true){
}
}
}).start();
}
}
<2>interrupt()方法
public class Interrupt {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(new Runnable() {
@Override
public void run() {
//...執(zhí)行任務(wù),執(zhí)行時(shí)間可能比較長(zhǎng)
//運(yùn)行到這里,在t的構(gòu)造方法中不能引用t使用Thread.currentThread()方法,獲取當(dāng)前代碼行所在線程的引用
for (int i = 0; i <10000&&!Thread.currentThread().isInterrupted() ; i++) {
System.out.println(i);
//模擬中斷線程
try {
Thread.sleep(1000);
//通過(guò)標(biāo)志位自行實(shí)現(xiàn),無(wú)法解決線程阻塞導(dǎo)致無(wú)法中斷
//Thread,sleep(100000)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();//線程啟動(dòng),中斷標(biāo)志位=false
System.out.println("t start");
//模擬,t執(zhí)行了5秒,進(jìn)程沒(méi)有結(jié)束,要中斷,停止t線程
Thread.sleep(5000);
//未設(shè)置時(shí),isInterrupt為false
//如果t線程處于阻塞狀態(tài)(休眠等),會(huì)拋出InterruptedException異常
//并且會(huì)重置isInterrupt中斷標(biāo)志位位false
t.interrupt();//告訴t線程,要中斷(設(shè)置t線程的中斷標(biāo)志位為true),由t的代碼自行決定是否要中斷
//isInterrupt設(shè)置為true
//t.isInterrupted(); Interrupted是線程中的標(biāo)志位
System.out.println("t stop");
//注:Thread.interrupted(); 返回當(dāng)前線程的中斷標(biāo)志位,然后重置中斷標(biāo)志位
}
}
<3>join方法
//join方法:實(shí)例方法:
// 1.無(wú)參:t.join:當(dāng)前線程無(wú)條件等待,直到t線程運(yùn)行完畢
// 2.有參:t.join(1000)等待1秒,或者t線程結(jié)束,哪個(gè)條件滿足,當(dāng)前線程繼續(xù)往下執(zhí)行
public class Join {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("1");
}
});
t.start();
t.join();//當(dāng)前線程main線程無(wú)條件等待,直到t線程執(zhí)行完畢,當(dāng)前線程再往后執(zhí)行
// t.join(1000);當(dāng)前線程等到1秒,或者等t線程執(zhí)行完畢
System.out.println("ok");
}
}
<4>獲取當(dāng)前線程的引用currentThread();方法
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.getName());
}
}
<5>休眠當(dāng)前線程sleep();方法
Thread.sleep(1000);
<6>線程讓步y(tǒng)ield();方法
public class Yield {
public static void main(String[] args) {
for(int i=0;i<20;i++){
final int n=i;
Thread t=new Thread(new Runnable() {
@Override
public void run() {
System.out.println(n);
}
});
t.start();
}
//判斷:如果活躍的線程數(shù)量大于1,main線程讓步
while (Thread.activeCount()>1){//記錄活躍線程的數(shù)量
Thread.yield();
}//注意:要用debug方式,因?yàn)閞un方式,idea后臺(tái)還會(huì)啟動(dòng)一個(gè)線程
//實(shí)現(xiàn)ok在1到二十之后打印
System.out.println("ok");
}
}
三.線程的生命周期和狀態(tài)轉(zhuǎn)換
四.線程間的通信
public class SequencePrintHomeWork {
//有三個(gè)線程,每個(gè)線程只能打印A,B或C
//要求:同時(shí)執(zhí)行三個(gè)線程,按ABC順序打印,依次打印十次
//ABC換行 ABC換行。。。。
//考察知識(shí)點(diǎn):代碼設(shè)計(jì),多線程通信
public static void main(String[] args) {
Thread a = new Thread(new Task("A"));
Thread b = new Thread(new Task("B"));
Thread c = new Thread(new Task("C"));
c.start();
b.start();
a.start();
}
private static class Task implements Runnable{
private String content;
//順序打印的內(nèi)容:可以循環(huán)打印
private static String[] ARR = {"A", "B", "C"};
private static int INDEX;//從數(shù)組哪個(gè)索引打印
public Task(String content) {
this.content = content;
}
@Override
public void run() {
try {
for(int i=0; i<10; i++){
synchronized (ARR){//三個(gè)線程使用同一把鎖
//從數(shù)組索引位置打印,如果當(dāng)前線程要打印的內(nèi)容不一致,釋放對(duì)象鎖等待
while(!content.equals(ARR[INDEX])){
ARR.wait();
}
//如果數(shù)組要打印的內(nèi)容和當(dāng)前線程要打印的一致,
// 就打印,并把數(shù)組索引切換到一個(gè)位置,通知其他線程
System.out.print(content);
if(INDEX==ARR.length-1){
System.out.println();
}
INDEX = (INDEX+1)%ARR.length;
ARR.notifyAll();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
五.多線程的安全及解決
1.原子性
2.可見性
3.代碼的順序性
4.線程不安全問(wèn)題的解決
<1>synchronized 關(guān)鍵字
<2>volatile 關(guān)鍵字
public class Test {
private static boolean flag = true;
public static void main(String[] args) {
//創(chuàng)建一個(gè)線程并啟動(dòng)
new Thread(new Runnable() {
int i=0;
@Override
public void run() {
while(flag){
//這個(gè)語(yǔ)句底層使用了synchronized,保證了可見性
//System.out.println("=============");
i++;
}
}
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//即使改了,上面的線程flag也不會(huì)改,會(huì)一直循環(huán)
flag = false;
}
}
六.鎖體系
1.Synchronized加鎖方式
<1>Synchronized的加鎖方式及語(yǔ)法基礎(chǔ)
public class SafeThread {
//有一個(gè)遍歷COUNT=0;同時(shí)啟動(dòng)20個(gè)線程,每個(gè)線程循環(huán)1000次,每次循環(huán)把COUNT++
//等待二十個(gè)子線程執(zhí)行完畢之后,再main中打印COUNT的值
//(預(yù)期)count=20000
private static int COUNT=0;
//對(duì)當(dāng)前類對(duì)象進(jìn)行加鎖,線程間同步互斥
// public synchronized static void increment(){
// COUNT++;
// }
//使用不同的對(duì)象加鎖,沒(méi)有同步互斥的效果,并發(fā)并行
// public static void increment(){
// synchronized (new SafeThread()){
// COUNT++;
// }
// }
public static void main(String[] args) throws InterruptedException {
//盡量同時(shí)啟動(dòng),不讓new線程操作影響
Class clazz=SafeThread.class;
Thread[]threads=new Thread[20];
for (int i = 0; i <20 ; i++) {
threads[i]=new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j <1000 ; j++) {
//給SafeThread對(duì)象加一把鎖
synchronized (clazz){
COUNT++;
}
}
}
});
}
for (int i = 0; i <20 ; i++) {
threads[i].start();
}
//讓main線程等待20個(gè)子線程運(yùn)行完畢
for (int i = 0; i <20 ; i++) {
threads[i].join();
}
System.out.println(COUNT);
}
}
<2>Synchronized的原理及實(shí)現(xiàn)
public class Test1 {
public Test1() {
}
public static void main(String[] args) {
Class var1 = Test1.class;
synchronized(Test1.class) {
System.out.println("hello");
}
}
}
<3>JVM對(duì)Synchronized的優(yōu)化
(1).對(duì)鎖的優(yōu)化
(2).鎖粗話
public class Test {
private static StringBuffer sb;
public static void main(String[] args) {
sb.append("1").append("2").append("3");
}
}
(3).鎖消除
public class Test {
public static void main(String[] args) {
StringBuffer sb=new StringBuffer();
sb.append("1");
sb.append("2");
sb.append("3");
}
}
2.常見的鎖策略及CAS
<1>.樂(lè)觀鎖和悲觀鎖
<2>自旋鎖
while(搶鎖(lock)==失敗{}
<3>可重入鎖
public class Test2 {
public static synchronized void t1(){
t2();
}
public static synchronized void t2(){
}
public static void main(String[] args) {
t1();
}
}
3.Lock體系
<1>Lock接口
(1)使用Lock鎖實(shí)現(xiàn)線程同步
public class AccountRunnable implements Runnable {
private Account account = new Account();
//買一把鎖
Lock lock = new ReentrantLock(); //Re-entrant-Lock 可重入鎖
@Override
public void run() {
//此處省略300句
try{
//上鎖
lock.lock();
//判斷余額是否足夠,夠,取之;不夠,不取之;
if(account.getBalance()>=400){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
method1();
//取之
account.withDraw(400);
//輸出信息
System.out.println(Thread.currentThread().getName()+
"取款成功,現(xiàn)在的余額是"+account.getBalance());
}else{
System.out.println("余額不足,"+Thread.currentThread().getName()
+"取款失敗,現(xiàn)在的余額是" +account.getBalance());
}
}finally {
//解鎖
lock.unlock();
}
//此處省略100句
}
}
(2)Lock加鎖的四種方式
<2>AQS簡(jiǎn)單認(rèn)識(shí)
<3>ReentrantLock
(1)ReentrantLock基本概念
(2)自己實(shí)現(xiàn)一個(gè)簡(jiǎn)單的ReentrantLock
public class Test2 {
volatile int status=0;
Queue parkQueue;//集合 數(shù)組 list
void lock(){
while(!compareAndSet(0,1)){
//這里不能用sleep或yield實(shí)現(xiàn)
//sleep無(wú)法確定睡眠的時(shí)間
//yield只能用于兩個(gè)線程競(jìng)爭(zhēng),當(dāng)有多個(gè)線程之后,t1搶不到鎖,yield會(huì)讓出cpu,但是可能下一次cpu還是調(diào)t1
park();
}
unlock();
}
void unlock(){
lock_notify();
}
void park(){
//將當(dāng)期線程加入到等待隊(duì)列
parkQueue.add(currentThread);
//將當(dāng)期線程釋放cpu 阻塞 睡眠
releaseCpu();
}
void lock_notify(){
//status=0
//得到要喚醒的線程頭部線程
Thread t=parkQueue.header();
//喚醒等待線程
unpark(t);
}
}
(3)ReentrantLock部分源碼分析
//非公平鎖
public ReentrantLock() {
sync = new NonfairSync();
}
//公平鎖
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
final void lock() {
if (compareAndSetState(0, 1))//首先用一個(gè)CAS操作,判斷state是否是0(表示當(dāng)前鎖未被占用)
setExclusiveOwnerThread(Thread.currentThread());//設(shè)置當(dāng)前占有鎖的線程為該線程
else
acquire(1);
}
public final void acquire(int arg) {
//首先看看自己要不要排隊(duì),如果不用排隊(duì),獲取鎖,要排隊(duì),加入AQS隊(duì)列
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire(arg)
final boolean nonfairTryAcquire(int acquires) {
//獲取當(dāng)前線程
final Thread current = Thread.currentThread();
//獲取state變量值
int c = getState();
if (c == 0) { //沒(méi)有線程占用鎖
if (compareAndSetState(0, acquires)) {
//占用鎖成功,設(shè)置獨(dú)占線程為當(dāng)前線程
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) { //當(dāng)前線程已經(jīng)占用該鎖 重入鎖
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// 更新state值為新的重入次數(shù)
setState(nextc);
return true;
}
//獲取鎖失敗
return false;
}
<4>ReadWriteLock鎖
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
public class TestLock {
public static void main(String[] args) {
//默認(rèn)也是非公平鎖 也是可重入鎖
ReadWriteLock rwl = new ReentrantReadWriteLock();
//多次返回的都是同一把讀鎖 同一把寫鎖
Lock readLock = rwl.readLock();
Lock readLock2 = rwl.readLock();
Lock writeLock = rwl.writeLock();
readLock.lock();
readLock.unlock();
System.out.println(readLock==readLock2);
}
}
4.Lock鎖和同步鎖(synchronized)的區(qū)別
5.死鎖
package threadadvanced.lesson1;
class Pen {
private String pen = "筆" ;
public String getPen() {
return pen;
}
}
class Book {
private String book = "本" ;
public String getBook() {
return book;
}
}
public class DeadLock {
private static Pen pen = new Pen() ;
private static Book book = new Book() ;
public static void main(String[] args) {
new DeadLock().deadLock();
}
public void deadLock() {
Thread thread1 = new Thread(new Runnable() { // 筆線程
@Override
public void run() {
synchronized (pen) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+" :我有筆,我就不給你");
synchronized (book) {
System.out.println(Thread.currentThread()+" :把你的本給我!");
}
}
}
},"Pen") ;
Thread thread2 = new Thread(new Runnable() { // 本子線程
@Override
public void run() {
synchronized (book) {
System.out.println(Thread.currentThread()+" :我有本子,我就不給你!");
synchronized (pen) {
System.out.println(Thread.currentThread()+" :把你的筆給我!");
}
}
}
},"Book") ;
thread1.start();
thread2.start();
}
}
七.多線程案例
1.生產(chǎn)者消費(fèi)者問(wèn)題
/**
* 面包店
* 10個(gè)生產(chǎn)者,每個(gè)每次生產(chǎn)3個(gè)
* 20個(gè)消費(fèi)者,每個(gè)每次消費(fèi)一個(gè)
*
* 進(jìn)階版需求
* 面包師傅每個(gè)最多生產(chǎn)30次,面包店每天生產(chǎn)10*30*3=900個(gè)面包
* 消費(fèi)者也不是一直消費(fèi)。把900個(gè)面包消費(fèi)完結(jié)束
*
* 隱藏信息:面包店每天生產(chǎn)面包的最大數(shù)量為900個(gè)
* 消費(fèi)者把900個(gè)面包消費(fèi)完結(jié)束
*/
public class AdvancedBreadShop {
//面包店庫(kù)存數(shù)
private static int COUNT;
//面包店生產(chǎn)面包的總數(shù),不會(huì)消費(fèi)的
private static int PRODUCE_NUMBER;
public static class Consumer implements Runnable{
private String name;
public Consumer(String name) {
this.name = name;
}
@Override
public void run() {
try {
while (true){
synchronized (AdvancedBreadShop.class){
if(PRODUCE_NUMBER==900&&COUNT==0){
System.out.println("今天面包已經(jīng)賣完了");
break;
}else {
if(COUNT==0){
AdvancedBreadShop.class.wait();
}else {
System.out.printf("%s消費(fèi)了一個(gè)面包\n",this.name);
COUNT--;
AdvancedBreadShop.class.notifyAll();
Thread.sleep(100);
}
}
}
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class Producer implements Runnable{
private String name;
public Producer(String name) {
this.name = name;
}
@Override
public void run() {
try {
//生產(chǎn)者生產(chǎn)30次,結(jié)束循環(huán)
for(int i=0;i<=30;i++) {
synchronized (AdvancedBreadShop.class){
if(i==30){
System.out.println("今天面包生產(chǎn)完了");
break;
}else {
if(COUNT>97){
AdvancedBreadShop.class.wait();
}else {
COUNT=COUNT+3;
PRODUCE_NUMBER=PRODUCE_NUMBER+3;
System.out.printf("%s生產(chǎn)了三個(gè)面包\n",this.name);
AdvancedBreadShop.class.notifyAll();
Thread.sleep(100);
}
}
}
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread[] Consumers=new Thread[20];
Thread[] Producers=new Thread[10];
for (int i = 0; i <20 ; i++) {
Consumers[i]=new Thread(new Consumer(String.valueOf(i)));
}
for (int i = 0; i <10 ; i++) {
Producers[i]=new Thread(new Producer(String.valueOf(i)));
}
for (int i = 0; i <20 ; i++) {
Consumers[i].start();
}
for (int i = 0; i <10 ; i++) {
Producers[i].start();
}
}
}2.單例模式
public class Singleton {
//volatile關(guān)鍵字修飾,保證的可見性和代碼的順序性
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
//判斷instance是否為空,競(jìng)爭(zhēng)鎖的條件
if (instance == null) {
//保證線程安全,為Singleton.class加鎖
synchronized (Singleton.class) {
//再次判斷instance是否為空,防止多個(gè)線程進(jìn)入第一個(gè)if后
//對(duì)synchronized鎖競(jìng)爭(zhēng)失敗進(jìn)入阻塞狀態(tài)后,再次進(jìn)入運(yùn)行態(tài)時(shí)
//new了多個(gè)Singleton,不符合單例模式
//保證線程安全
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
3.阻塞式隊(duì)列
/**
* 實(shí)現(xiàn)阻塞隊(duì)列
* 1.線程安全問(wèn)題:在多線程情況下,put,take不具有原子性,4個(gè)屬性,不具有可見性
* 2.put操作:如果存滿了,需要阻塞等待。take操作:如果是空,阻塞等待
* @param <T>
*/
public class MyBlockingQueue <T>{
//使用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列
private Object[] queue;
//存放元素的索引
private int putIndex ;
//取元素的索引
private int takeIndex;
//當(dāng)前存放元素的數(shù)量
private int size;
public MyBlockingQueue(int len){
queue=new Object[len];
}
//存放元素,需要考慮:
//1.putIndex超過(guò)數(shù)組長(zhǎng)度
//2.size達(dá)到數(shù)組最大長(zhǎng)度
public synchronized void put(T e) throws InterruptedException {
//不滿足執(zhí)行條件時(shí),一直阻塞等待
//當(dāng)阻塞等待都被喚醒并再次競(jìng)爭(zhēng)成功對(duì)象鎖,回復(fù)往下執(zhí)行時(shí),條件可能被其他線程修改
while (size==queue.length){
this.wait();
}
//存放到數(shù)組中放元素的索引位置
queue[putIndex]=e;
putIndex=(putIndex+1)%queue.length;
size++;
notifyAll();
}
//取元素
public synchronized T take() throws InterruptedException {
while (size==0){
this.wait();
}
T t= (T) queue[takeIndex];
queue[takeIndex]=null;
takeIndex=(takeIndex+1)%queue.length;
size--;
notifyAll();
return t;
}
public int size(){
return size;
}
public static void main(String[] args) {
MyBlockingQueue<Integer>queue=new MyBlockingQueue<>(10);
//多線程的調(diào)試方式:1.寫打印語(yǔ)句 2.jconsole
for (int i = 0; i <3 ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int j = 0; j <100 ; j++) {
queue.put(j);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
for (int i = 0; i <3 ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true){
int t= queue.take();
System.out.println(Thread.currentThread().getName()+":"+t);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
4.線程池
import java.util.concurrent.*;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
//以快遞公司,快遞員,快遞業(yè)務(wù)為模型
ThreadPoolExecutor pool=new ThreadPoolExecutor(
5,//核心線程數(shù)---->正式員工數(shù)
10,//最大線程數(shù)-->正式員工+臨時(shí)員工
60,//臨時(shí)工的最大等待時(shí)間
TimeUnit.SECONDS,//idle線程的空閑時(shí)間-->臨時(shí)工最大的存活時(shí)間,超過(guò)就解雇
new LinkedBlockingQueue<>(),//阻塞隊(duì)列,任務(wù)存放的地方--->快遞倉(cāng)庫(kù)
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(new Runnable() {
@Override
public void run() {
//r對(duì)象是線程池內(nèi)部封裝過(guò)的工作任務(wù)類(Worker),會(huì)一直循環(huán)等待的方式從阻塞隊(duì)列中拿取任務(wù)并執(zhí)行
//所以不能調(diào)用r.run();方法
System.out.println(Thread.currentThread().getName()+"開始執(zhí)行了");
}
});
}
},//創(chuàng)建線程的工廠類 線程池創(chuàng)建線程時(shí),調(diào)用該工廠類的方法創(chuàng)建線程(滿足該工廠創(chuàng)建線程的要求)
//---->對(duì)應(yīng)招聘員工的標(biāo)準(zhǔn)
/**
* 拒絕策略:達(dá)到最大線程數(shù)且阻塞隊(duì)列已滿,采取拒絕策略
* AbortPolicy:直接拋出RejectedExecutionException(不提供handler時(shí)的默認(rèn)策略)
* CallerRunsPolicy:誰(shuí)(某個(gè)線程)交給我(線程池)的任務(wù),我拒絕執(zhí)行,由誰(shuí)自己去執(zhí)行
* DiscardPolicy:交給我的任務(wù)直接丟棄掉
* DiscardOldestPolicy:阻塞隊(duì)列中最舊的任務(wù)丟棄
*/
new ThreadPoolExecutor.AbortPolicy()//拒絕策略-->達(dá)到最大線程數(shù),且阻塞隊(duì)列已滿,采取的拒絕策略
);//線程池創(chuàng)建以后,只要有任務(wù)們就會(huì)自動(dòng)執(zhí)行
for (int i = 0; i <20 ; i++) {
//線程池執(zhí)行任務(wù):execute方法,submit方法--->提交執(zhí)行一個(gè)任務(wù)
//區(qū)別:返回值不同
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
//線程池有4個(gè)快捷的創(chuàng)建方式(實(shí)際工作不使用,作為面試了解)
//實(shí)際工作需要使用ThreadPoolExecutor,構(gòu)造參數(shù)是我們自己指定,比較靈活
ExecutorService pool2=Executors.newSingleThreadExecutor();//創(chuàng)建單線程池
ExecutorService pool3=Executors.newCachedThreadPool();//緩存的線程池
ExecutorService pool5=Executors.newFixedThreadPool(4);//固定大小線程池
ScheduledExecutorService pool4=Executors.newScheduledThreadPool(4);//計(jì)劃任務(wù)線程池
//兩秒中之后執(zhí)行這個(gè)任務(wù)
pool4.schedule(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
}, 2, TimeUnit.SECONDS);
//一直執(zhí)行任務(wù)
pool4.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
}, 2, 1,TimeUnit.SECONDS);//比如一個(gè)腦子,兩秒后開始叫我,然后每隔一秒叫我一次
}
}
————————————————
版權(quán)聲明:本文為CSDN博主「Serendipity sn」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_45704528/article/details/117353110
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。
本文鏈接:
https://blog.csdn.net/qq_45704528/article/details/117353110


評(píng)論
圖片
表情























