提示:文章寫完後,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- 前言
- 一、什麼是程序什麼是線程?
- 二、思維導圖(1)多線程概述
- 二、用法介紹
-
- 1.Runnable
- 2.線程中斷與守護
- 3、線程安全
-
- 方式一同步代碼塊(隐式鎖)
- 方式二同步方法(隐式鎖)
- 方案三顯示鎖Lock
- 思維導圖(2)常用方法概述
- 思維導圖(3)線程池
-
- (1)緩存線程池
- (2) 定長線程池
- (3) 單線線程池
- (4) 緩存線程池
- 總結
前言
為什麼要使用多線程呢,在Java中多線程是指一個程序擁有多個線程,多線程程式并不能提高程式運作的速度,但能夠提高程式運作效率讓CPU的使用率更高。
注:歡迎各位指出錯誤
一、什麼是程序什麼是線程?
程序:是指一個記憶體中運作的程式,每個程序都有一個獨立的記憶體空間。
線程:是程序中的一個執行路徑,多個線程共享一個記憶體空間,線程之間可以互相切換,并發執行一個線程至少有一個線程。
二、思維導圖(1)多線程概述
為友善大家了解做了一份簡易思維導圖

二、用法介紹
1.Runnable
代碼如下(示例):
/**
* @author 26591
* 實作runnable與繼承thread相比有如下優勢
* 1. 通過建立任務然後給線程配置設定的方式來實作的多線程,更适合多個線程同時執行相同任務的情況。
* 2. 可以避免單繼承所帶來的局限性。
* 3. 任務與線程本身是分離的,提高了程式的健壯性。
*/
public class mainRunnable {
public static void main(String[] args) {
//實作Runnable
//1. 建立一個任務對象
Myrunnable r=new Myrunnable();
//2. 建立一個線程,并為其配置設定一個任務
Thread t=new Thread(r,"鋤禾日當午");
//thread.currentThread表示目前正在執行線程
System.out.println(Thread.currentThread().getName());
//3. 執行這個線程
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("汗滴禾下土"+i);
}
}
}
結果
2.線程中斷與守護
代碼如下(示例):
/**
* @author 26591
*/
public class ThreadInterrupt {
public static void main(String[] args) {
//線程的中斷
//一個線程是一個獨立的執行路徑,它是否應該結束,應該由其自身的決定
//線程分為守護線程和使用者線程
//守護線程:守護使用者線程,當最後一個使用者線程結束時,所有守護線程自動死亡。
Thread t1= new Thread(new MyRunnable());
//守護線程設定方式,main線程死亡t1線程自動結束
t1.setDaemon(true);
t1.start();
for (int i = 0; i <= 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//給線程t1打上中斷标記
t1.interrupt();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// e.printStackTrace();
//程式員可以控制線程是否繼續運作
System.out.println("檢查到标記我自殺了");
return;
}
}
}
}
}
本應該繼續執行的代碼當主程式執行完成後線程檢測到中斷标記自我中斷。
并且此處也表明了t1線程屬于守護線程就算是沒有中斷标記,當使用者線程也就是主線程結束後該線程也會自動消亡。
3、線程安全
方式一同步代碼塊(隐式鎖)
/**
* @author 26591
* 線程同步:synchronized
*/
public class ThreadSafetyDemo1 {
public static void main(String[] args) {
//線程不安全
//解決方案1.同步代碼塊
//格式:synchronized(鎖對象){}排隊執行
//任何對象都可以成為鎖對象
Runnable run=new Ticket();
//多個線程同時争搶同一資源時容易出現問題
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//票數
private int count = 10;
private Object o=new Object();
@Override
public void run() {
//注:使用同一把鎖要避免鎖對象不為一
//錯誤示例Object o=new Object();
while (true) {
//鎖對象
synchronized (o) {
if (count > 0) {
//賣票
System.out.println("正在準備賣票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,餘票:" + count);
}else {
break;
}
}
}
}
}
}
方式二同步方法(隐式鎖)
/**
* //使用synchronized (){}到方法
* @author 26591
*/
public class ThreadSafetyDemo2 {
public static void main(String[] args) {
//線程不安全
//解決方案2 同步方法
Runnable run=new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//票數
private int count = 10;
@Override
public void run() {
while (true) {
//鎖對象
boolean flag= sale();
if (!flag){//!flag=false
System.out.println("票已售空");
break;
}
}
}
public synchronized boolean sale(){
/*synchronized對象是調用者this
若被靜态修飾則為位元組碼同步對象例如
Ticket.class
*/
if (count > 0) {
//賣票
System.out.println("正在準備賣票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,餘票:" + count);
return true;
}else {
return false;
}
}
}
}
方案三顯示鎖Lock
public class ThreadSafetyDemo3 {
public static void main(String[] args) {
//線程不安全
// 解決方案3。顯示鎖 Lock 子類 Reentrantlock
//
Runnable run=new Ticket();
//多個線程同時争搶同一資源時容易出現問題
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//票數
private int count = 10;
//顯示鎖:參數為True表示 是公平鎖誰先來誰先得
private Lock l=new ReentrantLock();
@Override
public void run() {
while (true) {
//鎖住
l.lock();
//鎖對象
if (count > 0) {
//賣票
System.out.println("正在準備賣票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,餘票:" + count);
}else {
break;
}
l.unlock();
}
}
}
}
思維導圖(2)常用方法概述
思維導圖(3)線程池
1.如果并發的線程數量很多,并且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁建立線程 就會大大降低 系統的效率,因為頻繁建立線程和銷毀線程需要時間. 線程池就是一個容納多個線程的容 器,池中的線程可以反複使用,省去了頻繁建立線程對象的操作,節省了大量的時間和資源。
2.線程池的好處
降低資源消耗。
提高響應速度。
提高線程的可管理性
(1)緩存線程池
public class CacheThreadPool {
/**
* 緩存線程池。
* (長度無限制)
* 任務加入後執行的流程
* 1.判斷線程池是否存在空閑線程
* 2.存在則使用
* 3.不存在,則建立線程 并放入線程池,然後使用
* @param args
*/
public static void main(String[] args) {
ExecutorService service= Executors.newCachedThreadPool();
//指揮線程池中執行新的任務
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
//當最開始的三個線程執行完畢後此時線程池中擁有三個空閑線程選取其中一個執行下次任務
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
}
}
執行結果:
(2) 定長線程池
public class FixedLengthThreadPool {
/**
* 定長線程池
* (長度時指定的數值)
* 任務加入後的執行流程
* 1.判斷線程池是否存在空閑線程
* 2.存在即使用
* 3.不存在空閑線程,且線程池未免的情況下,則建立線程 并放入線程池,然後使用
* 4.不存在空閑線程,且線程池已滿的情況下,則等待線程池存在空閑線程
* @param args
*/
public static void main(String[] args) {
ExecutorService service= Executors.newFixedThreadPool(2);
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
}
}
執行結果:
(3) 單線線程池
public class SingleThreadPool {
/**
* 單線程線程池
* 執行流程:
* 1.判斷線程池 的那個線程 是否空閑
* 2.空閑則使用
* 3.不空閑,則等待 池中的單個線程空閑後 使用
*/
public static void main(String[] args) {
ExecutorService service= Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"鋤禾日當午");
}
});
}
}
執行結果:
(4) 緩存線程池
public class PeriodicFixedLengthTP {
/**
* 周期任務 定長線程池
* 執行流程:
* 1.判斷線程池是否存在空閑線程
* 2.存在即使用
* 3.不存在空閑線程,且線程池未滿的情況下,則建立線程 并放入線程池,然後使用
* 4.不存在空閑線程,且線程池已滿的情況下,則等線上程池存在空閑線程
*
* 周期性任務執行時:
* 定時執行,當某個時機觸發時,自動執行某任務。
* @param args
*/
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**
* 定時執行一次
* 參數1.定時執行的任務
* 參數2.時常數字
* 參數3.時常數字的時間機關TimeUnit的常量指定
service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("鋤禾日當午");
}
},5, TimeUnit.SECONDS);
*/
/**
* 周期性執行任務
* 參數1.任務
* 參數2.延遲時長數字(第一次執行在什麼時間以後)
* 參數3.周期性時長數字
* 參數4.時常數字的機關
*/
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("汗滴禾下土");
}
},3,1,TimeUnit.SECONDS);
}
}
執行結果:
總結
提示:這裡對文章進行總結:
例如:以上就是今天要講的内容,本文僅僅簡單介紹了JAVA多線程的使用,而JAVA多線程使我們快速便捷地處理資料的效率。