Java多執行緒(三)
目錄- Java多執行緒(三)
- 五、執行緒的通信
- 5.1 wait() 與 notify() 和 notifyAll() 介紹:
- 5.2 wait() 的使用:
- 5.3 notify() / notifyAll() 的使用
- 5.4 經典例題:生產者/消費者問題
- 六、JDK5.0新增多執行緒創建方式
- 6.1 多執行緒的創建方式之三:實作Callable介面
- 6.2 多執行緒的創建方式之四:使用執行緒池
- 五、執行緒的通信
五、執行緒的通信
5.1 wait() 與 notify() 和 notifyAll() 介紹:
- wait():令當前執行緒掛起并放棄CPU、同步資源并等待,使別的執行緒可訪問并修改共享資源,而當前執行緒排隊等候其他執行緒呼叫notify() 或 notifyAll() 方法喚醒,喚醒后等待重新獲得對監視器的所有權后才能繼續執行,
- notify():喚醒正在排隊等待同步資源的執行緒中優先級最高者結束等待,
- notifyAll ():喚醒正在排隊等待資源的所有執行緒結束等待,
-
這三個方法只有在 synchronized 方法 或 synchronized 代碼塊中才能使用,否則會報 java.lang.IllegalMonitorStateException例外,
-
因為這三個方法必須有鎖物件呼叫,而任意物件都可以作為 synchronized 的同步鎖, 因此這三個方法只能在Object類中宣告,
5.2 wait() 的使用:
- 在當前執行緒中呼叫方法: 物件名.wait() ,
- 使當前執行緒進入等待(某物件)狀態 ,直到另一執行緒對該物件發出 notify (或notifyAll) 為止,
- 呼叫方法的必要條件:當前執行緒必須具有對該物件的監控權(加鎖),
- 呼叫此方法后,當前執行緒將釋放物件監控權 ,然后進入等待,
- 在當前執行緒被 notify 后,要重新獲得監控權,然后從斷點處繼續代碼的執行,
5.3 notify() / notifyAll() 的使用
- 在當前執行緒中呼叫方法: 物件名.notify(),
- 功能:喚醒等待該物件監控權的一個/所有執行緒,
- 呼叫方法的必要條件:當前執行緒必須具有對該物件的監控權(加鎖),
5.4 經典例題:生產者/消費者問題
題目描述:
生產者(Productor)將產品交給店員(Clerk),而消費者(Customer)從店員處取走產品,店員一次只能持有固定數量的產品(比如:20),如果生產者試圖生產更多的產品,店員會叫生產者停一下,如果店中有空位放產品了再通知生產者繼續生產;如果店中沒有產品了,店員會告訴消費者等一下,如 果店中有產品了再通知消費者來取走產品,
class Clerk{
private int productCount = 0;
//生產產品
public synchronized void produceProduct() {
if(productCount < 20){
productCount++;
System.out.println(Thread.currentThread().getName() + ":開始生產第" + productCount + "個產品");
notify();
}else{
//等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//消費產品
public synchronized void consumeProduct() {
if(productCount > 0){
System.out.println(Thread.currentThread().getName() + ":開始消費第" + productCount + "個產品");
productCount--;
notify();
}else{
//等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Producer extends Thread{//生產者
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(getName() + ":開始生產產品.....");
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.produceProduct();
}
}
}
class Consumer extends Thread{//消費者
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(getName() + ":開始消費產品.....");
while(true){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.consumeProduct();
}
}
}
public class ProductTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p1 = new Producer(clerk);
p1.setName("生產者1");
Consumer c1 = new Consumer(clerk);
c1.setName("消費者1");
Consumer c2 = new Consumer(clerk);
c2.setName("消費者2");
p1.start();
c1.start();
c2.start();
}
}
六、JDK5.0新增多執行緒創建方式
6.1 多執行緒的創建方式之三:實作Callable介面
- 創建一個實作 Callable 的實作類
- 實作call方法,將此執行緒需要執行的操作宣告在call() 中,
- 創建 Callable 介面實作類的物件,
- 將此 Callable 介面實作類的物件作為傳遞到 FutureTask 構造器中,創建 FutureTask 的物件,
- 將 FutureTask 的物件作為引數傳遞到 Thread 類的構造器中,創建 Thread 物件,并呼叫 start() ,
- 獲取 Callable 中 call 方法的回傳值,(可選)
//1.創建一個實作Callable的實作類
class NumThread implements Callable{
//2.實作call方法,將此執行緒需要執行的操作宣告在call()中
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
if(i % 2 == 0){
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class ThreadNew {
public static void main(String[] args) {
//3.創建Callable介面實作類的物件
NumThread numThread = new NumThread();
//4.將此Callable介面實作類的物件作為傳遞到FutureTask構造器中,創建FutureTask的物件
FutureTask futureTask = new FutureTask(numThread);
//5.將FutureTask的物件作為引數傳遞到Thread類的構造器中,創建Thread物件,并呼叫start()
new Thread(futureTask).start();
try {
//6.獲取Callable中call方法的回傳值
//get()回傳值即為FutureTask構造器引數Callable實作類重寫的call()的回傳值,
Object sum = futureTask.get();
System.out.println("總和為:" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
-
與使用 Runnable 相比, Callable功能更強大些:
- 相比run()方法,可以有回傳值,
- 方法可以拋出例外,
- 支持泛型的回傳值,
- 需要借助 FutureTask 類,比如獲取回傳結果,
-
Future 介面:
- 可以對具體Runnable、Callable任務的執行結果進行取消、查詢是否完成、獲取結果等,
- FutrueTask 是 Futrue 介面的唯一的實作類,
- FutureTask 同時實作了Runnable, Future介面,它既可以作為 Runnable 被執行緒執行,又可以作為 Future 得到 Callable 的回傳值,
6.2 多執行緒的創建方式之四:使用執行緒池
-
執行緒池的引入:
經常創建和銷毀、使用量特別大的資源,比如并發情況下的執行緒, 對性能影響很大,
-
執行緒池的思路:
提前創建好多個執行緒,放入執行緒池中,使用時直接獲取,使用完放回池中,可以避免頻繁創建銷毀、實作重復利用,
-
使用執行緒池的好處:
-
提高回應速度(減少了創建新執行緒的時間)
-
降低資源消耗(重復利用執行緒池中執行緒,不需要每次都創建)
-
便于執行緒管理
corePoolSize:核心池的大小
maximumPoolSize:最大執行緒數
keepAliveTime:執行緒沒有任務時最多保持多長時間后會終止
-
-
執行緒池的使用:
(1)提供指定執行緒數量的執行緒池,
(2)執行指定的執行緒的操作,需要提供實作 Runnable 介面或 Callable 介面實作類的物件,
(3)關閉連接池,
class NumberThread implements Runnable{
@Override
public void run() {
for(int i = 0;i <= 100;i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
class NumberThread1 implements Runnable{
@Override
public void run() {
for(int i = 0;i <= 100;i++){
if(i % 2 != 0){
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
public class ThreadPool {
public static void main(String[] args) {
//1. 提供指定執行緒數量的執行緒池
ExecutorService service = Executors.newFixedThreadPool(10);
//2.執行指定的執行緒的操作,需要提供實作Runnable介面或Callable介面實作類的物件
service.execute(new NumberThread());//適合適用于Runnable
service.execute(new NumberThread1());//適合適用于Runnable
// service.submit(Callable callable);//適合使用于Callable
//3.關閉連接池
service.shutdown();
}
}
- 執行緒池相關API
- JDK 5.0 起提供了執行緒池相關API:ExecutorService 和 Executors ,
- ExecutorService:真正的執行緒池介面,常見子類 ThreadPoolExecutor,
// 執行任務/命令,沒有回傳值,一般用來執行 Runnable
void execute(Runnable command)
// 執行任務,有回傳值,一般又來執行 Callable
Future submit(Callable task)
// 關閉連接池
void shutdown()
- Executors:工具類、執行緒池的工廠類,用于創建并回傳不同型別的執行緒池,
// 創建一個可根據需要創建新執行緒的執行緒池
Executors.newCachedThreadPool()
// 創建一個可重用固定執行緒數的執行緒池
Executors.newFixedThreadPool(n)
// 創建一個只有一個執行緒的執行緒池
Executors.newSingleThreadExecutor()
// 創建一個執行緒池,它可安排在給定延遲后運行命令或者定期地執行,
Executors.newScheduledThreadPool(n)
-
執行緒池的屬性設定
-
ExecutorService 是一個介面,里面并沒有設定執行緒池屬性的方法,故不能用該介面的物件來對執行緒池進行屬性設定,
-
設定執行緒池屬性需要通過創建 ExecutorService 介面的實作類 ThreadPoolExecutor 的物件,呼叫該實作類的方法進行設定,
-
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
//設定執行緒池的屬性
service1.setCorePoolSize(15);
service1.setKeepAliveTime();
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/501071.html
標籤:其他
