本文目錄一覽:
北大青鳥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,分別建立程序模型,並通過多線程分別運行這幾個任務,那就簡單很多了。
多線程回顧筆記總結
三種創建方式:
// 練習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培訓學校告訴你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,分別建立程序模型,並通過多線程分別運行這幾個任務,那就簡單很多了。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/198361.html