Java執行緒基礎學習筆記(正在更新)
阿新 • • 發佈:2021-09-14
最近一直在跟著B站韓順平老師的《零基礎快速學Java》視訊教程學習Java基礎知識,教程地址——https://www.bilibili.com/video/BV1fh411y7R8?spm_id_from=333.999.0.0, 目前已經學到了程式程序執行緒基礎部分,在學習過程中做了一些相關的學習筆記和心得,分享在部落格,就當做是基礎強化了,哈哈哈。
執行緒基礎
1.執行緒介紹
1.1程序
程序是指執行中的程式,作業系統為啟動的程式分配記憶體空間;
程序是程式的一次執行過程,或是一個正在執行的程式。是一個動態的過程:有它自己的產生、存在和消亡的過程
1.2執行緒
執行緒由程序建立,是程序的一個實體
一個程序可以擁有多個執行緒
1.3併發與並行
併發:同一時刻,多個任務交替執行。單核CPU可以實現
並行:同一時刻,多個任務同時執行。多核CPU可以實現
2.執行緒使用
2.1繼承Thread建立執行緒
package thread; @SuppressWarnings({"all"}) /** * @Author Blueshadow * @Date 2021/7/26 9:24 * @Version 1.0 * * 程式啟動就開起了一個程序 * 進入到main方法之後,就開啟了一個主執行緒 * 通過hello.start()開啟了子執行緒Thread-0 */ public class thread { public static void main(String[] args) throws InterruptedException { Hello hello = new Hello();//建立一個物件,當做執行緒來使用 hello.start();//啟動子執行緒Thread-0 // hello.run();//此時run方法是一個普通的方法,沒有真正的啟動一個執行緒,等run方法執行完畢之後,才回去執行之後的程式碼(阻塞) //當main執行緒啟動一個子執行緒之後,主執行緒不會阻塞,會繼續執行,子執行緒和主執行緒交替執行 System.out.println("主執行緒"+Thread.currentThread().getName());//main for (int i = 0; i < 60 ; i++) { System.out.println("主執行緒 main 執行次數="+i); Thread.sleep(1000);//丟擲異常 } } } @SuppressWarnings({"all"}) //當一個類繼承了Thread方法,那麼該類可以當做一個執行緒類了 class Hello extends Thread{ @Override public void run() {//重寫run方法(該方法通過實現Runnable介面中的run方法),寫上自己的業務邏輯 int times = 0; while (true){ System.out.println("Hello world "+(++times) + "子執行緒名稱"+ Thread.currentThread().getName()); //讓執行緒休眠一秒 try {//通過try Catch處理異常 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }if (times == 80){ break;//當times等於80的時候,退出迴圈,此時執行緒也退出 } } } }
2.2多執行緒機制
//上面的程式通過hello.start()方法來實現多執行緒,因為如果直接呼叫執行緒類裡面的run方法的話,實現的就是一個主執行緒即main執行緒,而不是thread-0執行緒了,在底層,通過JVM來實現start方法,去啟東一個子執行緒
2.3實現Runnable介面建立執行緒
package thread; @SuppressWarnings({"all"}) /** * @Author Blueshadow * @Date 2021/7/26 9:24 * @Version 1.0 * * 通過實現介面Runnable來建立執行緒 */ public class thread { public static void main(String[] args) { Hello hello = new Hello(); // hello.start();//這裡不能呼叫start方法 Thread thread = new Thread(hello);//建立了一個Thread物件,把已經實現了Runnable介面的Hello物件放入Thread物件中 thread.start(); } } class Hello implements Runnable{ @Override public void run() { int num = 0; while (true){ System.out.println("hello"+(++num)+" 執行緒名稱>>>"+Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }if (num == 10){ break; } } } }
2.4多個子執行緒案例
package thread;
@SuppressWarnings({"all"})
/**
* @Author Blueshadow
* @Date 2021/7/26 9:24
* @Version 1.0
*
* 在main執行緒啟動兩個子執行緒
*/
public class thread {
public static void main(String[] args) {
Hello hello = new Hello();
World world = new World();
Thread thread1 = new Thread(hello);
Thread thread2 = new Thread(world);
thread1.start();
thread2.start();
}
}
class Hello implements Runnable{
@Override
public void run() {
int num = 0;
while (true){
System.out.println("Hello "+(++num)+"執行緒名:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}if (num == 10){
break;
}
}
}
}
class World implements Runnable{
@Override
public void run() {
int num = 0;
while (true){
System.out.println("world "+(++num)+"執行緒名:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}if (num == 5){
break;
}
}
}
}
2.5多執行緒售票問題
package thread;
@SuppressWarnings({"all"})
/**
* @Author Blueshadow
* @Date 2021/7/26 9:24
* @Version 1.0
*
* 使用多執行緒模擬三個視窗同時售票100張
*/
public class thread {
public static void main(String[] args) {
//建立視窗
SellTicket01 sellTicket01 = new SellTicket01();
SellTicket01 sellTicket02 = new SellTicket01();
SellTicket01 sellTicket03 = new SellTicket01();
//出現票數超賣問題,可以通過Synchronized來解決該問題(執行緒的同步和互斥)
sellTicket01.start();
sellTicket02.start();
sellTicket03.start();
}
}
//使用繼承Thread類建立執行緒
class SellTicket01 extends Thread{
private static int num = 100;//讓多個執行緒共享這個票數
@Override
public void run() {
while (true){
if (num <= 0){
System.out.println("售票結束");
break;
}
//售票休眠50毫秒
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("視窗 "+Thread.currentThread().getName()+"售出一張票"
+ "剩餘票數" +(--num)
);
}
}
}
2.6通知執行緒退出
執行緒完成之後自動退出
程式碼條件執行完畢,執行緒自動退出,但是主執行緒退出之後,子線執行緒不一定退出
通知執行緒退出
通過使用變數來控制run方法退出的方式停止執行緒
package thread;
@SuppressWarnings({"all"})
/**
* @Author Blueshadow
* @Date 2021/7/31 15:28
* @Version 1.0
*/
public class thread_exit {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.start();
Thread.sleep(10000);
//通過主執行緒控制子執行緒的終止,必須可以修改loop變數
//修改loop為false之後,退出run方法>>>通知方式
t.setLoop(false);
}
}
class T extends Thread{
//設定一個控制變數
private boolean loop = true;
@Override
public void run() {
int count = 0;
while (loop){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello world..."+(++count));
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
3.執行緒方法
3.1執行緒常用方法
setName//設定執行緒名稱,使之與引數name相同
getName//返回該執行緒的名字
start//使該執行緒開始執行;Java虛擬機器底層呼叫該diaman執行緒的start0()方法
run//呼叫執行緒物件run方法
setPriority//更改執行緒的優先順序
getPriority//獲取執行緒額優先順序
sleep//在指定的毫秒數內讓當前正在執行的執行緒休眠(即暫停執行)
interrupt//中斷執行緒
yield//執行緒的禮讓。讓出CPU,讓其他執行緒執行,但禮讓的時間不確定,所以不一定會禮讓成功
join//執行緒的插隊。插隊的執行緒一旦插隊成功,則一定會先執行完插入的執行緒的所有的任務
3.2執行緒中斷
package thread;
@SuppressWarnings({"all"})
/**
* @Author Blueshadow
* @Date 2021/7/31 15:28
* @Version 1.0
*/
public class thread_exit {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.setName("王帥");
t.setPriority(Thread.MIN_PRIORITY);//最小的優先順序
t.start();//啟動子執行緒
System.out.println("執行緒:"+t.getName()+"優先順序:"+t.getPriority());
//主執行緒列印五個語句,然後就中斷子執行緒的休眠
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
System.out.println("Hello..."+i);
}
t.interrupt();//main 執行緒中斷
System.out.println(Thread.currentThread().getName()+"...中斷");
}
}
class T extends Thread{//自定義執行緒類
@Override
public void run() {
while (true){
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+ "吃包子..." + i);
}
try {
System.out.println(T.currentThread().getName() + "休眠中...");
Thread.sleep(20000);
} catch (InterruptedException e) {
//當該執行緒執行到一個interrupt方法時,就會catch一個異常,可以加入自己的業務程式碼
//InterruptedException 捕獲到一箇中斷異常
e.printStackTrace();
System.out.println(Thread.currentThread().getName() + "被 interrupt");
}
}
}
}
3.3執行緒插隊
package thread;
@SuppressWarnings({"all"})
/**
* @Author Blueshadow
* @Date 2021/7/31 15:28
* @Version 1.0
*/
public class thread_exit {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.start();//啟動子執行緒
//讓子執行緒插隊到main執行緒前面,這樣,main執行緒就會等子執行緒執行完畢再執行
//如果沒有進行join,則主執行緒和子執行緒就會交替執行
for (int i = 0; i <= 20 ; i++) {
Thread.sleep(1000);
System.out.println("主執行緒吃 "+ i +" 個包子");
if (i == 5){
System.out.println("*****主執行緒吃了五個*****");
t.join();//插入執行緒,讓子執行緒執行完畢
}
}
}
}
class T extends Thread{//自定義執行緒類
@Override
public void run() {
for (int i = 0; i <= 20; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子執行緒吃了 " + i +" 個包子");//輸出子執行緒內容
}
}
}
3.4使用者執行緒和守護執行緒
使用者執行緒
也叫作工作執行緒,當執行緒的任務執行完或通知方式結束
守護執行緒
一般為工作執行緒服務,當所有的使用者執行緒結束,守護執行緒自動結束,常見的守護執行緒——垃圾回收機制
package thread;
@SuppressWarnings({"all"})
/**
* @Author Blueshadow
* @Date 2021/7/31 15:28
* @Version 1.0
*/
public class thread_exit {
public static void main(String[] args) throws InterruptedException {
T t = new T();
//將t設定成守護執行緒,當main程序結束之後(即所有執行緒結束之後),t執行緒也自動結束
t.setDaemon(true);
t.start();//啟動子執行緒
for (int i = 0; i <= 10 ; i++) {
Thread.sleep(1000);
System.out.println("Hello");
}
}
}
class T extends Thread{//自定義執行緒類
@Override
public void run() {
for ( ; ; ) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("World");
}
}
}
4.執行緒生命週期
JDK中用Thread.State列舉表示了執行緒的幾種狀態
NEW 尚未啟動的執行緒
RUNNABLE 在Java虛擬機器中執行的執行緒
BLOCKED 被阻塞等監視器鎖定的執行緒
WAITING 正在等待另一個執行緒執行特定動作的執行緒
TIME_WAITING 正在等待另一個執行緒執行動作達到指定等待時間的執行緒
TERMINATED 已退出的執行緒
5.Synchronized(執行緒同步機制)
在多執行緒程式設計,一些敏感資料不允許被多個執行緒同時訪問,此時就使用同步訪問技術,保證資料在任何時刻,最多有一個執行緒訪問,以保證資料的完成性;
當有一個執行緒在對記憶體進行操作時,其他執行緒都不可以對這個記憶體地址進行操作,直到該執行緒完成操作,其他執行緒才能對該記憶體地址進行操作。