java多執行緒併發及執行緒池
執行緒的常用建立方式
1、繼承Thread類建立執行緒類
public class FirstThreadTest extends Thread {
public void run(){
System.out.println("這裡是執行緒的執行方法");
}
public static void main(String[] args) {
//獲得執行緒
FirstThreadTest thread = new FirstThreadTest();
System.out.println("執行緒名稱為:" +thread.getName());
//啟動執行緒
thread.start();
System.out.println("main方法也是一個執行緒:"+Thread.currentThread().getName());
}
}
執行結果:
執行緒名稱為:Thread-0
main方法也是一個執行緒:main
這裡是執行緒的執行方法
2、通過Runnable介面建立執行緒類
(1)定義runnable介面的實現類,並重寫該介面的run()方法,該run()方法的方法體同樣是該執行緒的執行緒執行體;
(2)建立 Runnable實現類的例項,並依此例項作為Thread的target來建立Thread物件,該Thread物件才是真正的執行緒物件;
(3)呼叫執行緒物件的start()方法來啟動該執行緒。
public class RunnableThreadTest implements Runnable {
public void run() {
System.out.println("這裡是執行緒方法");
System.out.println("執行緒名為:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
System.out.println("main方法執行緒:" + Thread.currentThread().getName());
RunnableThreadTest rtt = new RunnableThreadTest();
new Thread(rtt, "新執行緒1").start();
new Thread(rtt, "新執行緒2").start();
}
}
執行結果
main方法執行緒:main
這裡是執行緒方法
執行緒名為:新執行緒1
這裡是執行緒方法
執行緒名為:新執行緒2
多執行緒併發
多執行緒併發出現問題主要涉及到兩個方面:多執行緒共享資料同步問題和資料因併發產生不一致問題;
1、多執行緒共享資料同步問題
如下程式碼:
/**
* 兩個工人一起搬磚
*/
public class Banzhuan {
public static void main(String[] args) {
// 一個工廠
Factory factory = new Factory();
/**
* p1執行緒和p2執行緒都是由factory這個例項建立的
* 那麼p1呼叫外部類的getZhuanTou()方法就相當於呼叫的是factory這個例項的getZhuanTou(),同樣的,p2呼叫的也是factory這個例項的getZhuanTou().
* 那麼這裡就出現了兩個執行緒同時訪問factory的getZhuanTou()方法。
* 而factory的getZhuanTou()方法又對zhuanTou這個屬性進行了zhuanTou--操作。
* 換句話說,兩個執行緒同時訪問了factory的資料zhuanTou.這時候就可能產生執行緒安全問題。
*/
// 同一個工廠的兩個工人
Person p1 = factory.getPerson();
Person p2 = factory.getPerson();
p1.start();
p2.start();
}
}
// 工廠
class Factory {
int zhuanTou = 20;// 一共20塊磚頭
public int getZhuanTou() {
if (zhuanTou == 0) {
throw new RuntimeException(Thread.currentThread().getName()+ ",沒有磚頭搬了!");
}
Thread.yield();
return zhuanTou--;
}
// 工人
class Person extends Thread {
// 不停的搬磚
public void run() {
while (true) {
// 獲取執行緒名(工人名) 及 剩下磚頭數
System.out.println(getName() + "搬了第" + getZhuanTou() + "塊磚頭");
// 當執行緒的run方法中出現了異常,且我們沒有 解決,那麼該執行緒終止並死亡。但不會影響 當前程序中的其他執行緒。
Thread.yield();
}
}
}
// 獲取工人
public Person getPerson() {
return new Person();
}
}
多次執行結果:
這裡並不是每次都會出錯,要多執行幾次,就會可能碰到多種錯誤,比如搬到了同一塊磚,比如少搬一塊磚,比如搬完到了0然後還有繼續搬……
原因是:比如現在還剩15塊磚頭,工人p1搬第15塊磚頭的時候正拿到手上,但是還沒有登記減少一塊磚頭(即還沒有執行zhuanTou–),這個時候工人p2也去拿磚,然後登記的時候一看還剩15塊磚頭,實際呢只剩14塊了……
解決方法:
synchronized:當它用來修飾一個方法或者一個程式碼塊的時候,能夠保證在同一時刻最多隻有一個執行緒執行該段程式碼。
所以將getZhuanTou()方法改成如下就可以了
public int getZhuanTou() {
synchronized (this) {
if (zhuanTou == 0) {
throw new RuntimeException(Thread.currentThread().getName()+",沒有磚頭搬了!");
}
Thread.yield();
return zhuanTou--;
}
}
為啥不將這個關鍵詞鎖在方法那呢?儘量將鎖在範圍最小的地方,這樣執行的效率更快。
首先,ThreadLocal 不是用來解決共享物件的多執行緒訪問問題的,一般情況下,通過ThreadLocal.set() 到執行緒中的物件是該執行緒自己使用的物件,其他執行緒是不需要訪問的,也訪問不到的。各個執行緒中訪問的是不同的物件;
另外,說ThreadLocal使得各執行緒能夠保持各自獨立的一個物件,並不是通過ThreadLocal.set()來實現的,而是通過每個執行緒中的new 物件的操作來建立的物件,每個執行緒建立一個,不是什麼物件的拷貝或副本。
再次,注意每一個執行緒都儲存一個物件的時候(非基本型別資料)應該是new一個新物件而不是引用一個物件,如下:
private static ThreadLocal<Index> local = new ThreadLocal<Index>() {
@Override
protected Index initialValue() {
return new Index(); //注意這裡
}
};
案例程式碼:
public class ThreadLocalTest {
//建立一個Integer型的執行緒本地變數
public static final ThreadLocal<Integer> local = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[5];
for (int j = 0; j < 5; j++) {
threads[j] = new Thread(new Runnable() {
@Override
public void run() {
//獲取當前執行緒的本地變數,然後累加5次
int num = local.get();
for (int i = 0; i < 5; i++) {
num++;
}
//重新設定累加後的本地變數
local.set(num);
System.out.println(Thread.currentThread().getName() + " : "+ local.get());
}
}, "Thread-" + j);
}
for (Thread thread : threads) {
thread.start();
}
}
}
執行結果:
Thread-0 : 5
Thread-4 : 5
Thread-2 : 5
Thread-1 : 5
Thread-3 : 5
--------------------------------------------------------------------------------------------------
3、總結:
ThreadLocal和Synchonized都用於解決多執行緒併發訪問。但是ThreadLocal與synchronized有本質的區別:
1、synchronized關鍵字主要解決多執行緒共享資料同步問題,ThreadLocal使用場合主要解決多執行緒中資料因併發產生不一致問題;
2、synchronized是利用鎖的機制,使變數或程式碼塊在某一時該只能被一個執行緒訪問。而ThreadLocal為每一個執行緒都提供了變數的副本,使得每個執行緒在某一時間訪問到的並不是同一個物件,這樣就隔離了多個執行緒對資料的資料共享。而Synchronized卻正好相反,它用於在多個執行緒間通訊時能夠獲得資料共享;
synchronized和ThreadLocal比較:http://blog.csdn.net/huyongl1989/article/details/8088841
執行緒池
當有許多請求需要去處理的時候,如果只是單獨的一個人去處理,可想而知那會讓後面在排隊的人等多久,這樣就需要執行緒池,有請求過來了就到執行緒池裡面取出一條執行緒去處理它,處理完成就把它收回到執行緒池裡面,然而自己實現 一個功能強大的執行緒池也並非易事,在java1.5之後專門提供了執行緒池的類庫。
Java通過Executors介面提供四種執行緒池,分別為:
newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒;
newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待;
newScheduledThreadPool 建立一個定長執行緒池,支援定時及週期性任務執行;
newSingleThreadExecutor 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行;
下面簡單看一下newFixedThreadPool這種執行緒池:
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.submit(new Runnable() {
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"---->"+index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
執行:
pool-1-thread-1—->0
pool-1-thread-3—->2
pool-1-thread-2—->1
pool-1-thread-3—->3
pool-1-thread-2—->5
pool-1-thread-1—->4
pool-1-thread-3—->6
pool-1-thread-1—->8
pool-1-thread-2—->7
pool-1-thread-3—->9
因為執行緒池大小為3,每個任務輸出index後sleep 2秒,所以每兩秒列印3個數字。
fixedThreadPool.submit(Runnable task)或者execute方法會呼叫執行緒的run方法;
相關推薦
java多執行緒併發及執行緒池
執行緒的常用建立方式 1、繼承Thread類建立執行緒類 public class FirstThreadTest extends Thread { public void run(){ System.out.println("這
Java多執行緒-併發之執行緒池
執行緒池有了解嗎? 答: java.util.concurrent.ThreadPoolExecutor 類就是一個執行緒池。客戶端呼叫ThreadPoolExecutor.submit(Runnable task) 提交任務,執行緒池內部維護的工作者執行緒的數量就是該執行緒池的執行
Java多執行緒-併發之執行緒和程序的區別
執行緒和程序的區別 答: 程序是一個“執行中的程式”,是系統進行資源分配和排程的一個獨立單位 執行緒是程序的一個實體,一個程序中擁有多個執行緒,執行緒之間共享地址空間和其他資源(所以通訊和同步等操作執行緒比程序更加容易) 執行緒上下文的切換比程序上下文切換要快
Java多執行緒併發01——執行緒的建立與終止,你會幾種方式
> 本文開始將開始介紹 Java 多執行緒與併發相關的知識,多謝各位一直以來的關注與支援。關注我的公眾號「Java面典」瞭解更多 Java 相關知識點。 # 執行緒的建立方式 在 Java 中,使用者常用的主動建立執行緒的方式有三種,分別是 **繼承 Thread 類**、**實現 Runnable 介面
多執行緒概述及執行緒的建立和啟動
多執行緒概述及執行緒的建立和啟動 概述 我們之前寫的程式都只是在做單執行緒的程式設計,所有的程式只有一條順序執行流,程式從main方法開始執行,依次向下執行每行程式碼,如果程式執行過程中某行程式碼遇到了阻塞,則程式將會停滯在該處。 單個執行緒往往功能非常有限,所以我們引入了多
執行緒併發工具--執行緒安全集合
一般的集合,如ArrayList、HashSet、HashMap等,都是執行緒不安全的。不安全的表現是什麼? ConcurrentModifyException 都知道,在遍歷集合的時候不能對集合進行新增和刪除操作,否則就會拋這個一場。如果一個執行緒正在遍歷一個集合的時候另
java多型的理解(執行時多型)
說道多型,一定離不開其它兩大特性:封裝和繼承。而多型是在它們的基礎之上表現而來的,息息相關。在記憶中,每一次學習面向物件的時候,都與這三大特性有扯不開的關係,其是面向物件的重點,當然也算是難點。但是,它們就像是一層窗戶紙,只要有一個縫隙,你就完全可以搞懂什麼是面向物件。下面來
java多線程優化及使用
int list() dex 執行 ret 我們 nbsp dem tar 一、多線程介紹 在編程中,我們不可逃避的會遇到多線程的編程問題,因為在大多數的業務系統中需要並發處理,如果是在並發的場景中,多線程就非常重要了。另外,我們在面試的時候,面試官通常也會問到我們關
Java多線程原理及Thread類的使用
默認 方法 繼承 class nbsp 技術 條件 其中 多線程技術 一、進程與線程的區別 1.進程是應用程序在內存總分配的空間。(正在運行中的程序) 2.線程是進程中負責程序執行的執行單元、執行路徑。 3.一個進程中至少有一個線程在負責進程的運行。 4.一個進程中
java多型引用場景及程式碼實現
class Test { public static void main(String[] args) { /** 動物類可以是狗 就吧狗創建出來 也叫向上轉型*/ Animal animalOne = new Dog(); /** 狗可以通用動物的
oracl執行sql檔案及執行亂碼解決
oracle執行sql檔案的兩個辦法,一直接複製到命令視窗,二使用start 絕對路徑 ,@絕對路徑。例如:@'C:\Users\Administrator\Desktop\test.sql' 其中第二個方法會出現亂碼錯誤,解決如下: 說明:本來想使用Navicat來以ut
Java多線程系列--“JUC線程池”03之 線程池原理(二)
.cn 創建 計數 dex unbound max strong 一點 rem 線程池示例 在分析線程池之前,先看一個簡單的線程池示例。 import java.util.concurrent.Executors; import java.util.concurrent.
多線程狀態及線程池管理
exe i/o wait 存儲 auto alt 周期 queue imu 一. 線程狀態類型 1. 新建狀態(New):新創建了一個線程對象。 2. 就緒狀態(Runnable):線程對象創建後,其他線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變
Java多線程系列--“JUC線程池”04之 線程池原理(三)
以及 java div 鉤子 重載 ati 系列 lex 基礎 轉自:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介紹線程池的生命周期。在"Java多線程系列--“基礎篇”01之 基本概念"中,我們介紹過,線程有
Java多線程系列--“JUC線程池”06之 Callable和Future
done ecan 對象 ava running 轉載 end 基於 處理 轉自:http://www.cnblogs.com/skywang12345/p/3544116.html 概要 本章介紹線程池中的Callable和Future。 Callable 和 Futu
Java多線程系列--“JUC線程池”01之 線程池架構
功能 err 一個表 @override 轉換 任務 新的 play ima 轉自:http://www.cnblogs.com/skywang12345/p/3509903.html 概要 前面分別介紹了"Java多線程基礎"、"JUC原子類"和"JUC鎖"。本章介紹JU
Java多執行緒程式設計核心技術(二)物件及變數的併發訪問
最近一直在忙比賽,四五個吧,時間有點緊張,部落格也沒時間更新~ 只能忙裡抽閒 本文屬於Java多執行緒程式設計系列的第二篇,旨在分享我對多執行緒程式設計技術的心得與感悟,順便做下筆記。 如果你閱讀完比較感興趣,歡迎關注我,等待更新後續篇章。 本文主要介紹Java多執行緒中的同步,也就是如何在Java語言中
【Java多執行緒程式設計核心技術】第二章 物件及變數的併發訪問
synchronized關鍵字 sychronized取得的鎖都是物件鎖,而不是把一段程式碼或方法(函式)當做鎖。 鎖重入功能:當一個執行緒得到一個物件鎖後,再次請求可以再次得到該物件的鎖 出現異常,鎖自動釋放 同步不具有繼承性 class Bas
JAVA模擬高併發及多執行緒計數器
1、多執行緒高併發模擬實現可採用閉鎖CountDownLatch,設定對應執行緒數的CountDownLatch,達到就緒條件後會多執行緒統一執行。這裡只是單機模擬,因為執行緒採用搶佔式執行方式,並不能完全模擬統一同時執行。 2、多執行緒計數器可採用悲觀鎖CAS實現類Ato
Java多執行緒之物件及變數的併發訪問
Java物件及變數的併發訪問 當多個執行緒同時對同一個物件中的例項變數進行併發訪問時可能會產生執行緒安全問題。產生的後果就是”髒讀”,即收到的資料其實是被更改過的。 如果訪問的是方法中的變數,則不存在”非執行緒安全”問題 可以通過以下幾種方式來解決,在對物