本文目錄一覽:
- 1、北大青鳥java培訓:Java多線程問題總結?
- 2、Java學習有哪些重點和難點
- 3、在 Java 程序中怎麼保證多線程的運行安全?
- 4、北大青鳥設計培訓:java多線程編程中涉及的基礎知識點?
- 5、多線程回顧筆記總結
- 6、什麼是Java多線程
北大青鳥java培訓:Java多線程問題總結?
Java多線程分類中寫了21篇多線程的文章,21篇文章的內容很多,個人認為,學習,內容越多、越雜的知識,越需要進行深刻的總結,這樣才能記憶深刻,將知識變成自己的。
java課程培訓機構認為這篇文章主要是對多線程的問題進行總結的,因此羅列了多個多線程的問題。
這些多線程的問題,有些來源於各大網站、有些來源於自己的思考。
(1)發揮多核CPU的優勢隨著工業的進步,現在的筆記本、台式機乃至商用的應用伺服器至少也都是雙核的,4核、8核甚至16核的也都不少見,如果是單線程的程序,那麼在雙核CPU上就浪費了50%,在4核CPU上就浪費了75%。
單核CPU上所謂的」多線程」那是假的多線程,同一時間處理器只會處理一段邏輯,只不過線程之間切換得比較快,看著像多個線程」同時」運行罷了。
多核CPU上的多線程才是真正的多線程,它能讓你的多段邏輯同時工作,多線程,可以真正發揮出多核CPU的優勢來,達到充分利用CPU的目的。
(2)防止阻塞從程序運行效率的角度來看,單核CPU不但不會發揮出多線程的優勢,反而會因為在單核CPU上運行多線程導致線程上下文的切換,而降低程序整體的效率。
但是單核CPU我們還是要應用多線程,就是為了防止阻塞。
試想,如果單核CPU使用單線程,那麼只要這個線程阻塞了,比方說遠程讀取某個數據吧,對端遲遲未返回又沒有設置超時時間,那麼你的整個程序在數據返回回來之前就停止運行了。
多線程可以防止這個問題,多條線程同時運行,哪怕一條線程的代碼執行讀取數據阻塞,也不會影響其它任務的執行。
(3)便於建模這是另外一個沒有這麼明顯的優點了。
假設有一個大的任務A,單線程編程,那麼就要考慮很多,建立整個程序模型比較麻煩。
但是如果把這個大的任務A分解成幾個小任務,任務B、任務C、任務D,分別建立程序模型,並通過多線程分別運行這幾個任務,那就簡單很多了。
Java學習有哪些重點和難點
Java學習第一個重點難點——JDK開發環境安裝
首先是Java開發環境的各種版本選擇,一般情況下我們需要從JDK官網下載最新版本的JDK文件(但是還需要注意你所學習的圖書或者視頻使用的是哪個版本的JDK),根據自己電腦的系統選擇對應的安裝包。
其次在安裝過程中一定要設置環境變數的路徑,這個過程非常關鍵,會直接影響你的JDK是否可以正常使用。最終還要在「命令提示符」中驗證,是否已經真正地完成了JDK的安裝。
Java學習第二個重點難點——變數的理解
變數是入門Java開發的首個概念性的思維轉變,目前所有的編程語言都是完成人類語言到機器語言的轉變過渡方式。變數則是貫穿整個Java編程開發的核心知識點。例如變數的各種不同的類型、變數的命名規則、變數之間的轉換、變數賦值時的初始化的理解,變數的相關運算符的使用等等。
Java學習第三個重點難點——OOP面向對象編程思想
Java作為高級編程語言,最大的特點就是採用面向對象編程思想,與面向過程的編程方法相比,OOP能夠大幅度的提高代碼運行效率。在面向對象中需要重點理解類、對象、抽象類、介面、封裝、集成和多態的概念。在Java編程開發中,大部分實戰項目都是採用面向對象的思維進行開發,因此重點理解和掌握OOP是學習Java編程開發的重中之重。所以掌握面向對象的概念並且能夠熟練運用是一個Java開發工程師最基本要求。在學習過程中,應該儘可能多地去進行實操練習。
Java學習第四個重點難點——多線程
在大型項目中,多線程是眾多Java程序員的技術門檻,單純的概念理解可能並不是很困難,最重要的是要掌握多線程的核心原理以及多線程的實際應用。包括多線程的創建、現成的 生命周期、鎖的概念、線程安全等問題。在實際編程開發中,多線程是出現BUG最多的位置,而避免BUG出現的最好方法就是深刻理解多線程的原理,總結歸納多線程經常出現異常的位置,並快速響應找到對應的解決方案。
Java學習中的第五個重點難點——異常
異常是每一個Java開發者不可避免的問題。包括Error、Runtime Exception、Exception、throw自定義異常等等。之前接觸到很多同學遇到異常就會手忙腳亂,其實大部分異常都是可以通過調式解決掉,也有很多異常是由於開發者的編碼錯誤引發的,因此遇到異常首先要分析異常產生的原因,逐層去調式獲取引發異常的位置,然後不斷的總結歸納引發異常的各種原因,在學習工作中不斷的提高自己解決問題的能力。學習異常的方法有兩種,一種就是系統地去了解各種異常的種類,並理解其引發異常的原因,在實際遇到問題的時候先套用方法,然後再尋找不同的解決方案。另外一種方法就是學習中進行大量的練習,在練習過程中遇到異常後根據實際情況去排查異常產生原因並總結歸納。
Java學習中的其他重點難點
雖然在文中沒有重點提到循環、構造函數、I/O和序列化、各種設計模式等等關鍵內容。對於初學者來說,每一個新的知識點都有一個理解到運用的過程,最重要的是能在學習中掌握所學知識點的底層原理和實際應用。Java編程開發作為一門實操性非常強的技術,單純的理論知識無法支撐你的快速就業,能夠真正動手編碼並實現相應的功能才是學習Java最終的目的。
在 Java 程序中怎麼保證多線程的運行安全?
零基礎學習java可按照這份大綱來進行學習
第一階段:Java專業基礎課程
階段目標:
1. 熟練掌握Java的開發環境與編程核心知識
2. 熟練運用Java面向對象知識進行程序開發
3. 對Java的核心對象和組件有深入理解
4. 熟練應用JavaAPI相關知識
5. 熟練應用JAVA多線程技術
6. 能綜合運用所學知識完成一個項目
知識點:
1、基本數據類型,運算符,數組,掌握基本數據類型轉換,運算符,流程式控制制。
2、數組,排序演算法,Java常用API,類和對象,了解類與對象,熟悉常用API。
3、面向對象特性,集合框架,熟悉面向對象三大特性,熟練使用集合框架。
4、IO流,多線程。
5、網路協議,線程運用。
第二階段:JavaWEB核心課程
階段目標:
1. 熟練掌握資料庫和MySQL核心技術
2. 深入理解JDBC與DAO資料庫操作
3. 熟練運用JSP及Servlet技術完成網站後台開發
4. 深入理解緩存,連接池,註解,反射,泛型等知識
5. 能夠運用所學知識完成自定義框架
知識點:
1、資料庫知識,範式,MySQL配置,命令,建庫建表,數據的增刪改查,約束,視圖,存儲過程,函數,觸發器,事務,游標,建模工具。
2、深入理解資料庫管理系統通用知識及MySQL資料庫的使用與管理。為Java後台開發打下堅實基礎。Web頁面元素,布局,CSS樣式,盒模型,JavaScript,jQuery。
3、掌握前端開發技術,掌握jQuery。
4、Servlet,EL表達式,會話跟蹤技術,過濾器,FreeMarker。
5、掌握Servlet相關技術,利用Servlet,JSP相關應用技術和DAO完成B/S架構下的應用開發。
6、泛型,反射,註解。
7、掌握JAVA高級應用,利用泛型,註解,枚舉完成自己的CRUD框架開發為後續框架學習做鋪墊。
8、單點登錄,支付功能,項目整合,分頁封裝熟練運用JSP及Servlet核心知識完成項目實戰。
第三階段:JavaEE框架課程
階段目標:
1. 熟練運用Linux操作系統常見命令及完成環境部署和Nginx伺服器的配置
2. 熟練運用JavaEE三大核心框架:Spring,SpringMVC,MyBatis
3. 熟練運用Maven,並使用SpringBoot進行快速框架搭建
4. 深入理解框架的實現原理,Java底層技術,企業級應用等
5. 使用Shiro,Ztree和Spring,SpringMVC,Mybaits完成企業項目
知識點:
1、Linux安裝配置,文件目錄操作,VI命令,管理,用戶與許可權,環境部署,Struts2概述,hiberante概述。
2、Linux作為一個主流的伺服器操作系統,是每一個開發工程師必須掌握的重點技術,並且能夠熟練運用。
3、SSH的整合,MyBatis,SpringMVC,Maven的使用。
4、了解AOP原理,了解中央控制器原理,掌握MyBatis框架,掌握SSM框架的整合。
5、Shiro,Ztree,項目文檔,項目規範,需求分析,原型圖設計,資料庫設計,工程構建,需求評審,配置管理,BUG修復,項目管理等。
6、獨立自主完成一個中小型的企業級綜合項目的設計和整體架構的原型和建模。獨立自主完成一個大型的企業級綜合項目,並具備商業價值
北大青鳥設計培訓:java多線程編程中涉及的基礎知識點?
線程設計在軟體開發領域中是非常常見的一個設計構成,今天合肥北大青鳥就一起來了解一下,java多線程編程中都涉及到了哪些基礎知識點。
順序用於表示多個操作「依次處理」。
比如把十個操作交給一個人來處理時,這個人要一個一個地按順序來處理並行用於標識多個操作「同時處理」。
比如十個操作分給兩個人處理時,這兩個人就會並行來處理。
並發相對於順序和並行來說比較抽象,用於表示「將一個操作分割成多個部分並且允許無序處理」。
比如將十個操作分成相對獨立的兩類,這樣便能夠開始並發處理了。
如果一個人來處理,這個人就是順序處理分開的並發操作,而如果是兩個人,這兩個人就可以並行處理同一個操作。
總結多線程程序都是並發處理的。
如果CPU只有一個,那麼並發處理就是順序執行的,而如果有多個CPU,那麼並發處理就可能會並行運行。
等待隊列所有實例都擁有一個等待隊列,它是在實例的wait方法執行後停止操作的線程隊列。
就好比為每個實例準備的線程休息室在執行wait方法後,線程便會暫停操作,進入等待隊列這個休息室。
除非發生下列某一情況,否則線程會一直在等待隊列中休眠。
有其他線程的notify方法來喚醒線程有其他線程的notifyAll方法來喚醒線程有其他線程的interrupt方法來喚醒線程wait方法超時notify方法該方法會將等待隊列中的一個線程去除。
同wait方法一樣,若要執行notify方法,線程也必須持有要調用的實例的鎖。
notifyAll方法notify方法僅喚醒一個線程,而notifyAll則喚醒所有線程,這是兩者之間的區別同wait方法和notify方法一樣,notifyAll方法也只能由持有要調用的實例鎖的線程調用notify和notifyAll選擇notify方法和notifyAll方法非常相似,到底該使用哪個?實際上,這很難選擇,由於notify喚醒的線程較少,所以處理速度要比使用notifyAll時快。
但使用notify時,如果處理不好,程序便可能會停止。
一般來說,使用notifyAll時的代碼要比使用notify時的更為健壯。
多線程回顧筆記總結
三種創建方式:
// 練習Thread,實現多線程同步下載圖片
public class TestThread1 extends Thread {
private String name; // 保存文件名
// 創建一個構造器
public TestThread1(String url, String name) {
this.url = url;
this.name = name;
}
public static void main(String[] args) {
TestThread1 testThread1 = new TestThread1(“;z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=4spn=0di=179850pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1462782358%2C2840615474os=332435882%2C2135675601simid=3516664974%2C458125993adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3B8-jyj_z%26e3BvgAzdH3FQQ%25E0%25l9%25AF%25EF%25Bl%25ba%25E0%25ln%25A0%25Em%25BE%25Bm%25Em%25lD%25l8%25Ec%25b9%25lA_z%26e3Bip4sgsm=5islist=querylist=”,”1.jpg”);
TestThread1 testThread2 = new TestThread1(“;z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=8spn=0di=18480pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1756505232%2C2129310927os=3725694615%2C3696011658simid=3576571828%2C474240706adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3F80qq_z%26e3Bv54AzdH3Fqqp57xtwg2AzdH3F8899l9m_rn_z%26e3Bip4sgsm=5islist=querylist=”,”2.jpg”);
TestThread1 testThread3 = new TestThread1(“;z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=25spn=0di=132220pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1226648351%2C4217836os=1652635041%2C3404961290simid=3325093720%2C338083432adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bprbb_z%26e3BgjpAzdH3Fp57xtwg2p7rtwgAzdH3Fgwgfijg2p57xtwg2AzdH3Fda8lAzdH3F8d89AzdH3F8dnb0_z%26e3Bip4sgsm=5islist=querylist=”,”3.jpg”);
testThread1.start();
testThread2.start();
testThread3.start();
/* 結果,說明線程不是按代碼先後順序執行的,是同時執行的
下載了文件,名為:3.jpg
下載了文件,名為:1.jpg
下載了文件,名為:2.jpg
*/
}
// 下載圖片的線程執行體
@Override
public void run() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downLoader(url,name);
System.out.println(“下載了文件,名為:”+name);
}
}
// 下載器
class WebDownLoader {
// 下載方法
public void downLoader(String url,String name) {
try {
// copyURLToFile(),這個方法就是把網上的一個url變成一個文件
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println(“IO異常,downLoader方法出錯”);
}
}
}
// 創建線程方式2:實現Runnable介面,重寫run()方法,執行線程需要丟入Runnable介面實現類,調用start()方法
public class TestThread2 implements Runnable {
public static void main(String[] args) {
// 創建Runnable 介面實現類對象
TestThread2 testThread2 = new TestThread2();
// 創建線程對象,通過線程對象來開啟我們的線程,代理
Thread thread = new Thread(testThread2);
thread.start();
//new Thread(testThread2).start(); // 簡寫方法
for (int i = 0; i 2000; i++) {
System.out.println(“我們在學習多線程—“+i);
}
}
@Override
public void run() {
for (int i = 0; i 2000; i++) {
System.out.println(“我們在玩 遊戲 啦—“+i);
}
}
}
發現問題:多個線程操作同一個資源情況下,線程不安全,數據紊亂,出現重複數據
// 模擬龜兔賽跑
public class Race implements Runnable {
// 勝利者
private static String winner;
@Override
public void run() {
for (int i = 0; i = 100) {
winner = Thread.currentThread().getName();
System.out.println(“winner is ” + winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, “兔子”).start();
new Thread(race, “烏龜”).start();
}
}
關閉服務:executorService.shutdownNow();
// 線程創建方式三:實現Callable介面
/*
* Callable的好處
* 1.可以定義返回值
* 2.可以拋出異常
**/
public class TestCallable implements Callable {
private String name; // 保存文件名
// 創建一個構造器
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable testThread1 = new TestCallable(“;z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=4spn=0di=179850pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1462782358%2C2840615474os=332435882%2C2135675601simid=3516664974%2C458125993adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3B8-jyj_z%26e3BvgAzdH3FQQ%25E0%25l9%25AF%25EF%25Bl%25ba%25E0%25ln%25A0%25Em%25BE%25Bm%25Em%25lD%25l8%25Ec%25b9%25lA_z%26e3Bip4sgsm=5islist=querylist=”,”1.jpg”);
TestCallable testThread2 = new TestCallable(“;z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=8spn=0di=18480pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1756505232%2C2129310927os=3725694615%2C3696011658simid=3576571828%2C474240706adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3F80qq_z%26e3Bv54AzdH3Fqqp57xtwg2AzdH3F8899l9m_rn_z%26e3Bip4sgsm=5islist=querylist=”,”2.jpg”);
TestCallable testThread3 = new TestCallable(“;z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=25spn=0di=132220pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1226648351%2C4217836os=1652635041%2C3404961290simid=3325093720%2C338083432adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bprbb_z%26e3BgjpAzdH3Fp57xtwg2p7rtwgAzdH3Fgwgfijg2p57xtwg2AzdH3Fda8lAzdH3F8d89AzdH3F8dnb0_z%26e3Bip4sgsm=5islist=querylist=”,”3.jpg”);
// 創建執行服務
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 提交執行
Future submit1 = executorService.submit(testThread1);
Future submit2 = executorService.submit(testThread2);
Future submit3 = executorService.submit(testThread3);
// 獲取結果
Boolean b1 = submit1.get();
Boolean b2 = submit2.get();
Boolean b3 = submit3.get();
// 關閉服務
executorService.shutdownNow();
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
/* 結果,說明線程不是按代碼先後順序執行的,是同時執行的
下載了文件,名為:3.jpg
下載了文件,名為:1.jpg
下載了文件,名為:2.jpg
*/
}
// 下載圖片的線程執行體
@Override
public Boolean call() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downLoader(url,name);
System.out.println(“下載了文件,名為:”+name);
return true;
}
}
// 下載器
class WebDownLoader {
// 下載方法
public void downLoader(String url,String name) {
try {
// copyURLToFile(),這個方法就是把網上的一個url變成一個文件
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println(“IO異常,downLoader方法出錯”);
}
}
}
靜態代理模式總結:
真實對象和代理對象都要實現同一個介面
代理對象要代理真實角色
代理模式的好處:
代理對象可以做很多真實對象做不了的事情
真實對象專註做自己的事情就可以了, 其他的事情交給代理公司來做
new Thread(()- System.out.println(“我愛你啊”)).start();
public abstract void run();
}
五大狀態:
// 測試Stop
// 1.建議線程正常停止,利用次數,不建議死循環
// 2.建議使用標誌位,設置一個標誌位
// 3.不要使用stop(),destroy()方法,已過時
public class StopTest implements Runnable {
// 1 設置一個標誌位
private boolean flag = true;
public static void main(String[] args) {
StopTest stopTest = new StopTest();
// 開啟線程
new Thread(stopTest).start();
for (int i = 0; i 1000; i++) {
System.out.println(“main Thread is running…”+i);
if (i == 900) {
// 調用stop方法切換標誌位停止線程
stopTest.stop();
System.out.println(“Thread is stopped…”);
}
}
}
// 設置一個公開的方法停止線程,轉換標誌位
public void stop() {
this.flag = false;
}
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println(“Thread is running…”+ i++);
}
}
}
yield
jion
daemon
// 化妝的方法,互相持有對方的鎖,就是需要拿到對方的資源
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) { // 獲得口紅的鎖
System.out.println(this.girlName+”獲得口紅的鎖”);
Thread.sleep(1000);
synchronized (mirror) { // 一秒後想獲得鏡子的鎖
System.out.println(this.girlName+”獲得鏡子的鎖”);
}
}
} else {
synchronized (mirror) { // 獲得鏡子的鎖
System.out.println(this.girlName+”獲得鏡子的鎖”);
Thread.sleep(2000);
synchronized (lipstick) { // 一秒後想獲得口紅的鎖
System.out.println(this.girlName+”獲得口紅的鎖”);
}
}
}
}
這樣synchronized 塊包裹著,就會導致程序卡死,只要不包裹著,就可以正常運行,如下:
// 死鎖,多個線程互相抱著對方需要的資源,然後形成僵持
public class DeadLock {
public static void main(String[] args) {
Makeup bestGirl = new Makeup(0, “婕兒”);
Makeup betterGirl = new Makeup(1, “珂兒”);
bestGirl.start();
betterGirl.start();
}
}
// 口紅
class Lipstick {
}
// 鏡子
class Mirror {
}
// 化妝
class Makeup extends Thread {
// 需要的資源只有一份,用static來保證只有一份
static Mirror mirror = new Mirror();
static Lipstick lipstick = new Lipstick();
int choice; // 選擇
String girlName; // 使用化妝品的人
public Makeup(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
// 化妝
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 化妝的方法,互相持有對方的鎖,就是需要拿到對方的資源
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) { // 獲得口紅的鎖
System.out.println(this.girlName+”獲得口紅的鎖”);
Thread.sleep(1000);
}
synchronized (mirror) { // 一秒後想獲得鏡子的鎖
System.out.println(this.girlName+”獲得鏡子的鎖”);
}
} else {
synchronized (mirror) { // 獲得鏡子的鎖
System.out.println(this.girlName+”獲得鏡子的鎖”);
Thread.sleep(2000);
}
synchronized (lipstick) { // 一秒後想獲得口紅的鎖
System.out.println(this.girlName+”獲得口紅的鎖”);
}
}
}
}
上面列出了死鎖的四個條件,我們只要想辦法破其中任意一個,或多個條件就可以避免死鎖發生
1.這是一個線程同步問題,生產者和消費者共享同一個資源,並且生產者和消費者之間相互依賴,互為條件.
2.Java提供了幾個方法解決線程之間的通信問題
3.解決方式1
並發協作模型「生產者/消費者模式」 —管程法
生產者將生產好的數據放入緩衝區,消費者從緩衝區拿出數據
4.解決方式2
// 測試線程池
public class PoolTest {
public static void main(String[] args) {
// 創建服務,創建池子
// newFixedThreadPool,參數為:線程池池子大小
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多線程
多線程的概念?
說起多線程,那麼就不得不說什麼是線程,而說起線程,又不得不說什麼是進程。
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。
進程可以簡單的理解為一個可以獨立運行的程序單位。它是線程的集合,進程就是有一個或多個線程構成的,每一個線程都是進程中的一條執行路徑。
那麼多線程就很容易理解:多線程就是指一個進程中同時有多個執行路徑(線程)正在執行。
為什麼要使用多線程?
1.在一個程序中,有很多的操作是非常耗時的,如資料庫讀寫操作,IO操作等,如果使用單線程,那麼程序就必須等待這些操作執行完成之後才能執行其他操作。使用多線程,可以在將耗時任務放在後台繼續執行的同時,同時執行其他操作。
2.可以提高程序的效率。
3.在一些等待的任務上,如用戶輸入,文件讀取等,多線程就非常有用了。
缺點:
1.使用太多線程,是很耗系統資源,因為線程需要開闢內存。更多線程需要更多內存。
2.影響系統性能,因為操作系統需要在線程之間來回切換。
3.需要考慮線程操作對程序的影響,如線程掛起,中止等操作對程序的影響。
4.線程使用不當會發生很多問題。
總結:多線程是非同步的,但這不代表多線程真的是幾個線程是在同時進行,實際上是系統不斷地在各個線程之間來回的切換(因為系統切換的速度非常的快,所以給我們在同時運行的錯覺)。
2.多線程與高並發的聯繫。
高並發:高並髮指的是一種系統運行過程中遇到的一種「短時間內遇到大量操作請求」的情況,主要發生在web系統集中大量訪問或者socket埠集中性收到大量請求(例如:12306的搶票情況;天貓雙十一活動)。該情況的發生會導致系統在這段時間內執行大量操作,例如對資源的請求,資料庫的操作等。如果高並發處理不好,不僅僅降低了用戶的體驗度(請求響應時間過長),同時可能導致系統宕機,嚴重的甚至導致OOM異常,系統停止工作等。如果要想系統能夠適應高並髮狀態,則需要從各個方面進行系統優化,包括,硬體、網路、系統架構、開發語言的選取、數據結構的運用、演算法優化、資料庫優化……。
而多線程只是在同/非同步角度上解決高並發問題的其中的一個方法手段,是在同一時刻利用計算機閑置資源的一種方式。
多線程在高並發問題中的作用就是充分利用計算機資源,使計算機的資源在每一時刻都能達到最大的利用率,不至於浪費計算機資源使其閑置。
3.線程的創建,停止,常用方法介紹。
1.線程的創建:
線程創建主要有2種方式,一種是繼承Thread類,重寫run方法即可;(Thread類實現了Runable介面)
另一種則是實現Runable介面,也需要重寫run方法。
線程的啟動,調用start()方法即可。 我們也可以直接使用線程對象的run方法,不過直接使用,run方法就只是一個普通的方法了。
其他的還有: 通過匿名內部類的方法創建;實現Callable介面。。。。。
2.線程常用方法:
currentThread()方法:該方法返回當前線程的信息 .getName()可以返回線程名稱。
isAlive()方法:該方法判斷當前線程是否處於活動狀態。
sleep()方法:該方法是讓「當前正在執行的線程「休眠指定的時間,正在執行的線程是指this.currentThread()返回的線程。
getId()方法:該方法是獲取線程的唯一標識。
3.線程的停止:
在java中,停止線程並不簡單,不想for。。break那樣說停就停,需要一定的技巧。
線程的停止有3種方法:
1.線程正常終止,即run()方法運行結束正常停止。
2.使用interrupt方法中斷線程。
3.使用stop方法暴力停止線程。
interrupt方法中斷線程介紹:
interrupt方法其實並不是直接中斷線程,只是給線程添加一個中斷標誌。
判斷線程是否是停止狀態:
this.interrupted(); 判斷當前線程是否已經中斷。(判斷的是這個方法所在的代碼對應的線程,而不是調用對象對應的線程)
this.isInterrupted(); 判斷線程是否已經中斷。(誰調用,判斷誰)
註:.interrupted()與isInterrupted()的區別:
interrupted()方法判斷的是所在代碼對應的線程是否中斷,而後者判斷的是調用對象對應的線程是否停止
前者執行後有清除狀態的功能(如連續調用兩次時,第一次返回true,則第二次會返回false)
後者沒有清除狀態的功能(兩次返回都為true)
真正停止線程的方法:
異常法:
在run方法中 使用 this.interrupted();判斷線程終止狀態,如果為true則 throw new interruptedException()然後捕獲該異常即可停止線程。
return停止線程:
在run方法中 使用 this.interrupted();判斷線程終止狀態,如果為true則return停止線程。 (建議使用異常法停止線程,因為還可以在catch中使線程向上拋,讓線程停止的事件得以傳播)。
暴力法:
使用stop()方法強行停止線程(強烈不建議使用,會造成很多不可預估的後果,已經被標記為過時)
(使用stop方法會拋出 java.lang.ThreadDeath 異常,並且stop方法會釋放鎖,很容易造成數據不一致)
註:在休眠中停止線程:
在sleep狀態下停止線程 會報異常,並且會清除線程狀態值為false;
先停止後sleep,同樣會報異常 sleep interrupted;
4.守護線程。
希望對您有所幫助!~
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/236685.html