1、多線程的創建
注意:線程開啟不一定立即執行,由CPU調度執行
1.1創建方式一
繼承Thread類,重寫run()方法,調用start()方法開啟線程。
package SunThread;
public class Thread_01 extends Thread{
@Override
public void run() {
//run方法線程體
for (int i = 0; i < 20; i++) {
System.out.println("我在寫代碼!");
}
}
public static void main(String[] args) {
//main線程,主線程
//創建線程對象
Thread_01 thread_01 = new Thread_01();
//調用start開啟線程
thread_01.start();
for (int i = 0; i < 20; i++) {
System.out.println("我在學JAVA");
}
}
}
多次運行發現(最好修改循環輸出次數多一點),輸出結果一般會不同,原因就是CPU在進行線程的調度。
1.2創建方式二(建議使用)
實現Runnable接口,重寫run()方法,實現接口需要丟入Runnable接口實現類,調用start()方法開啟線程。
package SunThread;
public class Thread_03 implements Runnable{
@Override
public void run() {
//run方法線程體
for (int i = 0; i < 20; i++) {
System.out.println("我在寫代碼");
}
}
public static void main(String[] args) {
//main線程,主線程
//創建ruunnable實現類對象
Thread_03 thread_03 = new Thread_03();
//創建線程對象通過線程對象實現我們的接口類
//Thread thread = new Thread(thread_03);
//thread.start();
new Thread(thread_03).start();//與上兩行實現的結果是一樣的
for (int i = 0; i < 100; i++) {
System.out.println("我在學JAVA");
}
}
}
推薦使用:實現Runable()接口,因為可以有效的避免單繼承的局限性,靈活方便,方便同一個對象被多個線程使用
1.3創建方式三(不經常使用)
與使用runnable方式相比,callable功能更強大些:call方法可以有返回值,方法可以拋出異常,支持泛型的返回值,需要借助FutureTask類,獲取返回結果等。
運用三個線程下載網絡圖片的方式,對Callable實現接口類的方式進行解釋,(代碼直接復制運行不了)。
package SunThread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
public class Thread_05 implements Callable<Boolean> {
private String url;//下載的網絡圖片地址
private String name;//保存的文件名
public Thread_05(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() throws Exception {
WebDownloader webDownloader = new WebDownloader();
webDownloader.Downloader(url,name);
System.out.println("文件name為"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//new 3個Callable接口的對象
Thread_05 t1 = new Thread_05("https://img-blog.csdnimg.cn/20201029222157503.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NVTl9fQ0dK,size_16,color_FFFFFF,t_70#pic_center","1.jpg");
Thread_05 t2 = new Thread_05("https://img-blog.csdnimg.cn/20201029222523262.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NVTl9fQ0dK,size_16,color_FFFFFF,t_70#pic_center","2.jpg");
Thread_05 t3 = new Thread_05("https://img-blog.csdnimg.cn/20201029222403840.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NVTl9fQ0dK,size_16,color_FFFFFF,t_70#pic_center","3.jpg");
//創建固定線程個數為3個的線程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
//提交執行線程,最多3個
Future<Boolean> s1 = executorService.submit(t1);
Future<Boolean> s2 = executorService.submit(t2);
Future<Boolean> s3 = executorService.submit(t3);
//獲取相應的結果
boolean rs1=s1.get();
boolean rs2=s2.get();
boolean rs3=s3.get();
//關閉線程池
executorService.shutdown();
}
}
//具體的下載方法,使用時需要導入commons—IO-2.6.jar包
class WebDownloader{
public void Downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:中間並發進行的接口對象,根據自己需要進行修改。
2、線程五大狀態
2.1線程的停止(stop)
1.建議線程正常停止―>利用次數,不建議死新環.
2.建議使用標志位--->設置一個標志位
3.不要使用stop或者destroy等過時或者JDK不建議使用的方法
package SunThread;
//測試線程停止
public class Threadstop_01 implements Runnable{
private boolean flag=true;
@Override
public void run() {
int i=0;
while (flag){
System.out.println("我在測試線程停止"+i++);
}
}
public void stop(){
this.flag=false;
}
public static void main(String[] args) {
Threadstop_01 threadstop_01 = new Threadstop_01();
new Thread(threadstop_01).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if(i==900)
{
threadstop_01.stop();
System.out.println("線程停止了");
}
}
}
}
2.2線程的休眠(sleep)
1、sleep(時間)指定當前線程阻塞的毫秒數;
2、sleep存在異常InterruptedException;
3、sleep時間達到后線程進入就緒狀態;
4、sleep可以模擬網絡延時,倒計時等。
5、每一個對象都有一個鎖,sleep不會釋放鎖;
package SunThread;
//runnable實現買票過程
//sleep放大問題的發生性
public class Thread_04 implements Runnable{
private int a=10;
@Override
public void run() {
while(a>0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+a--+"張票");
}
}
public static void main(String[] args) {
Thread_04 thread_04 = new Thread_04();
new Thread(thread_04,"小明").start();
new Thread(thread_04,"小李").start();
new Thread(thread_04,"小紅").start();
}
}
注:sleep放大問題的發生性,運用sleep可以編寫倒計時、模擬網絡延時等等。
2.3線程的禮讓(yield)
1、禮讓線程,讓當前正在執行的線程暫停,但不阻塞;
2、將線程從運行狀態轉為就緒狀態;
3、讓CPU重新調度,禮讓不一定成功!看CPU心情
package SunThread;
import javax.xml.transform.sax.SAXSource;
public class ThreadYield_01 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"該線程開始執行!");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"該線程停止執行!");
}
public static void main(String[] args) {
ThreadYield_01 threadYield_01 = new ThreadYield_01();
new Thread(threadYield_01,"A").start();
new Thread(threadYield_01,"B").start();
}
}
禮讓不一定會成功
2.4線程的強制執行(join)
1、Join合並線程,待此線程執行完成后,再執行其他線程,其他線程阻塞
2、可以想象成插隊
package SunThread;
public class ThreadJoin_01 implements Runnable{
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 1000; i++) {
System.out.println("線程vip來了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
ThreadJoin_01 threadJoin_01 = new ThreadJoin_01();
Thread thread = new Thread(threadJoin_01);
thread.start();
for (int i = 0; i < 1000; i++) {
if(i==500)
{
thread.join();
}
System.out.println("main"+i);
}
}
}
由於現在CPU一般多核進行處理,我們可以在run()方法中設置一個休眠時間。
3、線程的狀態
3.1運用代碼的輸出線程狀態
1、NEW 尚未啟動的線程處於此狀態。
2、RUNAABLE 在Java虛擬機中執行的線程處於此狀態。
3、BLOCKED 被阻塞等待監視器鎖定的線程處於此狀態。
4、WAITING 正在等待另一個線程執行特定動作的線程處於此狀態。
5、TIMED_WAITING 正在等待另一個線程執行動作達到指定等待時間的線程處於此狀態。
6、TEPM4INATED 已退出的線程處於此狀態。
package SunThread;
public class Thread_06 {
public static void main(String[] args) throws InterruptedException {
//運用lambda表達式對方法進行簡化
Thread thread=new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("==========");
});
//觀察狀態
Thread.State state = thread.getState();
System.out.println(state);//期待輸出NEW
//觀察啟動后
thread.start();
state = thread.getState();
System.out.println(state);//RUN
while(state!=thread.getState().TERMINATED)
{
thread.sleep(200);
state = thread.getState();
System.out.println(state);//RUN
}
}
}
4、線程的優先級
4.1設置優先級並輸出
Java提供一個線程調度器來監控程序中啟動后進入就緒狀態的所有線程,線程調度器按照優先級決定應該調度哪個線程來執行。
線程的優先級用數字表示,范圍從1~10.
Thread.MIN_PRIORITY= 1;
Thread.MAX_PRIORITY= 10;
Thread.MAX_PRIORITY= 10;
getPriority() . setPriority(int xxx)
優先級的設定建議在start()調度前
package SunThread;
public class ThreadPriority_01 {
public static void main(String[] args) {
//主線程優先級
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
Thread t5 = new Thread(myPriority);
Thread t6 = new Thread(myPriority);
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);//Thread.MAX_PRIORITY=10
t4.start();
t5.setPriority(8);
t5.start();
t6.setPriority(7);
t6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
優先級低只是意味着獲得調度的概率低.並不是優先級低就不會被調用了.這都是看CPU的調度
優先級的設定建議在start()調度
5、線程的守護
5.1代碼解釋線程的守護
1、線程分為用戶線程和守護線程
2、虛擬機必須確保用戶線程執行完畢
3、虛擬機不用等待守護線程執行完畢
4、如,后台記錄操作日志,監控內存,垃圾回收等待!.
package SunThread;
public class ThreadDaemon_01 {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
thread.setDaemon(true);//默認為false,默認為用戶線程,設置為守護線程
thread.start();
new Thread(you).start();
}
}
class God implements Runnable{
@Override
public void run() {
while (true)
{
System.out.println("上帝守護者你!");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("生活了"+i+"天");
}
System.out.println("goodbye world!");
}
}
6、線程的同步機制
6.1線程的同步理解
由於我們可以通過private 關鍵字來保證數據對象只能被方法訪問﹐所以我們只需要針對方法提出一套機制,這套機制就是synchronized關鍵字,它包括兩種用法:synchronized方法和synchronized塊.
同步方法:public synchronized void method(int args)0{}
synchronized方法控制對“對象”的訪問,每個對象對應一把鎖,每個synchronized方法都必須獲得調用該方法的對象的鎖才能執行﹐否則線程會阻塞,方法一旦執行﹐就獨占該鎖,直到該方法返回才釋放鎖﹐后面被阻塞的線程才能獲得這個鎖,繼續執行.
缺陷:若將一個大的方法申明為synchronized將會影響效率
6.2線程的不安全性
用到lambda表達式簡化https://blog.csdn.net/SUN__CGJ/article/details/109406652
package SunThread;
import java.util.ArrayList;
public class Thread_07 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
//lambda表達式簡化
new Thread(()->{list.add(Thread.currentThread().getName())}).start();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
期待輸出9999,但是輸出只有9994,這就是線程的不安全性。
6.3實現線程同步
同步塊 :synchronized (Obj ){}
Obj稱之為同步監視器
Obj可以是任何對象﹐但是推薦使用共享資源作為同步監視器
同步方法中無需指定同步監視器﹐因為同步方法的同步監視器就是this ,就是這個對象本身﹐或者是class [反射中講解]
同步監視器的執行過程
1.第一個線程訪問﹐鎖定同步監視器﹐執行其中代碼.
2第二個線程訪問﹐發現同步監視器被鎖定﹐無法訪問.
3.第一個線程訪問完畢﹐解鎖同步監視器.
4.第二個線程訪問,發現同步監視器沒有鎖,然后鎖定並訪問
package SunThread;
import java.util.ArrayList;
public class Thread_07 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
//lambda表達式簡化
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
這樣就是與我們的期待值相符合了。簡單理解就是加鎖,鎖的是所需要操作的對象。
補充:
運用JUC並發編程實現同步。
package SunThread;
import java.util.concurrent.CopyOnWriteArrayList;
public class Thread_08 {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
7、線程的死鎖狀態
7.1死鎖
多個線程各自占有一些共享資源﹐並且互相等待其他線程占有的資源才能運行﹐而導致兩個或者多個線程都在等待對方釋放資源﹐都停止執行的情形.某一個同步塊同時擁有“兩個以上對象的鎖”時,就可能會發生“死鎖”的問題.
產生死鎖的四個必要條件:
1.互斥條件:一個資源每次只能被一個進程使用。
2.請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
3.不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
4.循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。
用兩個小孩想吃蘋果和香蕉進行解釋
package SunThread;
public class DeadLock_01 {
public static void main(String[] args) {
Eat e1 = new Eat(0, "小明");
Eat e2 = new Eat(2, "小紅");
e1.start();
e2.start();
}
}
class Apple{ }
class Banana{ }
class Eat extends Thread{
static Apple apple=new Apple();
static Banana banana=new Banana();
int choice;
String name;
Eat(int choice,String name){
this.choice=choice;
this.name=name;
}
@Override
public void run() {
try {
eating();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void eating() throws InterruptedException {
if(choice==0){
synchronized (apple){
System.out.println(this.name+"獲得蘋果的鎖");
Thread.sleep(1000);
synchronized (banana){
System.out.println(this.name+"獲得香蕉的鎖");
}
}
}
else{
synchronized (banana){
System.out.println(this.name+"獲得香蕉的鎖");
Thread.sleep(2000);
synchronized (apple){
System.out.println(this.name+"獲得蘋果的鎖");
}
}
}
}
}
期待輸出:
小明獲得蘋果的鎖
小紅獲得香蕉的鎖
小明獲得香蕉的鎖
小紅獲得蘋果的鎖
但是輸出的不一樣,而且程序在一直運行。
解決方法:
package SunThread;
public class DeadLock_01 {
public static void main(String[] args) {
Eat e1 = new Eat(0, "小明");
Eat e2 = new Eat(2, "小紅");
e1.start();
e2.start();
}
}
class Apple{ }
class Banana{ }
class Eat extends Thread{
static Apple apple=new Apple();
static Banana banana=new Banana();
int choice;
String name;
Eat(int choice,String name){
this.choice=choice;
this.name=name;
}
@Override
public void run() {
try {
eating();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void eating() throws InterruptedException {
if(choice==0){
synchronized (apple){
System.out.println(this.name+"獲得蘋果的鎖");
}
Thread.sleep(1000);
synchronized (banana){
System.out.println(this.name+"獲得香蕉的鎖");
}
}
else{
synchronized (banana){
System.out.println(this.name+"獲得香蕉的鎖");
}
Thread.sleep(2000);
synchronized (apple){
System.out.println(this.name+"獲得蘋果的鎖");
}
}
}
}
7、Lock鎖
從JDK 5.0開始,Java提供了更強大的線程同步機制——通過顯式定義同步鎖對象來實現同步。同步鎖使用Lock對象充當
java.util.concurrent.locks.Lock接口是控制多個線程對共享資源進行訪問的工具。鎖提供了對共享資源的獨占訪問,每次只能有一個線程對Lock對象加鎖,線程開始訪問共享資源之前應先獲得Lock對象
ReentrantLock類實現了Lock,它擁有與synchronized相同的並發性和內存語義,在實現線程安全的控制中,比較常用的是ReentrantLock,可以顯式加鎖、釋放鎖。
買票的例子進行解釋。
package SunThread;
import java.util.concurrent.locks.ReentrantLock;
public class TeskLock_01 {
public static void main(String[] args) {
TeskLock teskLock = new TeskLock();
new Thread(teskLock, "小明").start();
new Thread(teskLock, "小李").start();
new Thread(teskLock, "小紅").start();
}
}
class TeskLock implements Runnable {
private int a = 10;
//定義lock
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();//加鎖
try {
if(a>0) {
Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + "拿到了第" + a-- + "張票");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();//解鎖
}
}
}
}
符合常理。
8、生產者與消費者問題
8.1應用場景:生產者消費者問題
-
1、假設倉庫中只能存放一件產品,生產者將生產出來的產品放入倉庫,消費者將倉庫中產品取走消費.
-
2、如果倉庫中沒有產品,則生產者將產品放入倉庫,否則停止生產並等待,直到倉庫中的產品被消費者取走為止.
-
3、如果產品中放有產品,則消費者可以將產品取走消費,否則停止消費並等待,直到倉庫再次放入產品為止.
-
Java提供了幾個方法解決線程之間的通信問題
-
8.2管程法進行實現
生產者:負責生產數據的模塊(可能是方法,對象,線程,進程)
消費者:負責處理數據的模塊(可能是方法,對象,線程,進程)
緩沖區:消費者不能直接使用生產者的數據,他們之間有個緩沖區,生產者將生產好的數據放入緩沖區,消費者從緩沖區拿出數據
樣例思路:
1.首先有一個生產者,消費者、生產者只顧生產,消費者只管消費、
2.利用了一個緩沖區,緩沖了一個10個大小的數組
3.有個方法叫放入產品,產品丟進來的時候,我們判斷一下緩沖區有沒有滿,如果滿了的話,生產者就要等待了,
如果沒有滿,就將產品放進去,放進去之后有產品了,趕緊通知消費者消費
4.消費者就判斷下能不能消費呢,有沒有東西,有東西的話,我就可以直接消費,消費完了,就趕緊通知生產者生產。
如果沒有東西呢,消費者就等待。等待生產者去通知他,生產者通知了,他就可以解除等待了
package SunThread;
//測試: 生產者消費者模型-->利用緩沖區解決:管程法
//生產者 , 消費者 , 產品 , 緩沖區
public class TestPC {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生產者
class Productor extends Thread {
SynContainer container;
public Productor(SynContainer container) {
this.container = container;
}
//生產
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.push(new Chicken(i));
System.out.println("生產了" + i + "只雞");
}
}
}
//消費者
class Consumer extends Thread {
SynContainer container;
public Consumer(SynContainer container) {
this.container = container;
}
//消費
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消費了-->" + container.pop().id + "只雞");
}
}
}
//產品
class Chicken {
int id;//編號
public Chicken(int id) {
this.id = id;
}
}
//緩沖區
class SynContainer {
//需要一個容器大小
Chicken[] chickens = new Chicken[10];
//容器計數器
int count = 0;
//生產者放入產品
public synchronized void push(Chicken chicken) {
//如果容器滿了,就需要等待消費者消費
if (count == chickens.length) {
//生產者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果沒有滿,我們需要丟入產品
chickens[count] = chicken;
count++;
//可以通知消費者消費了.
this.notifyAll();
}
//消費者消費產品
public synchronized Chicken pop() {
//判斷能否消費
if (count == 0) {
//消費者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消費
count--;
Chicken chicken = chickens[count];
//吃完了,通知生產者生產
this.notifyAll();
return chicken;
}
}
8.3信號燈法
來判斷一個標志位flag,如果為true,就讓他等待、如果為false,就讓他去通知另外一個人、把兩人銜接起來,就像咱們的信號燈紅燈停,綠燈行,通過這樣一個判斷方式,只要來判斷什么時候讓他等待,什么時候將他喚醒就ok。
package SunThread;
//測試生產者消費者問題2:信號燈法,通過標志位解決
public class TestPC_01 {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生產者-->演員
class Player extends Thread {
TV tv;
public Player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
this.tv.play("快樂大本營播放中");
} else {
this.tv.play("抖音:記錄美好生活");
}
}
}
}
//消費者-->觀眾
class Watcher extends Thread {
TV tv;
public Watcher(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//產品-->節目
class TV {
//演員表演,觀眾等待 T
//觀眾觀看,演員等待 F
String voice; // 表演的節目
boolean flag = true;
//表演
public synchronized void play(String voice) {
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演員表演了:" + voice);
//通知觀眾觀看
this.notifyAll();
this.voice = voice;
this.flag = !this.flag;
}
//觀看
public synchronized void watch() {
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("觀看了:" + voice);
//通知演員表演
this.notifyAll();
this.flag = !this.flag;
}
}
9、線程池
9.1用Runable實現線程池
-
背景:經常創建和銷毀、使用量特別大的資源,比如並發情況下的線程,對性能影響很大
-
思路:提前創建好多個線程,放入線程池中,使用時直接獲取,使用完放回池中。可以避免頻繁創建銷毀、實現重復利用。類似生活中公共交通工具。
-
好處:
提高響應速度(減少了創建線程的時間)
降低資源的消耗(重復利用線程池中線程,不需要每次都創建)
便於線程管理(...)
corePoolSize:核心池的大小
maximumPoolSize:最大線程數
keepAliveTime:線程沒有任務時最多保持多長時間后會終止
-
JDK 5.0起提供了線程池相關API:ExecutorService 和 Executors
-
ExecutorService:真正的線程池接口。常見子類ThreadPoolExecutor
-
void execute(Runnable command):執行任務/命令,沒有返回值,一 般用來執行Runnable
-
Future submit(Callable task):執行任務,有返回值,一般用來執行Callable -
void shutdown():關閉連接池
6.Executors:工具類、線程池的工廠類、用於創建並返回不同類型的線程池
用Runable實現線程池
package SunThread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//測試線程池
public class TestPool {
public static void main(String[] args) {
//1.創建服務,創建線程池
//newFixedThreadPool(10); 參數為線程池的大小
ExecutorService service = Executors.newFixedThreadPool(10);
//執行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2.關閉連接
service.shutdown();
}
}
class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
自學習於嗶哩嗶哩狂神說JAVA(侵刪);
作為自己的筆記,歡迎大家斧正!