日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java多线程--多线程基础小结

發布時間:2025/4/14 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java多线程--多线程基础小结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是線程?

?? 在同一個進程中可以執行多個任務,每一個任務可以看做一個線程.

? 線程是程序的執行單元,執行路徑,使程序使用cpu的最基本單位

? 一個進程如果只有一條執行路徑,那么就是單線程的

一個進程如果有多個執行路徑,那么就是多線程的

多線程的意義:

?? 多進程的存在是為了提高CPU的利用率,多線程的存在,不是為了提高程序的執行速度,而是為了提高應用程序的使用率.

?? 程序的執行其實都是在搶CPU的資源,即CPU的執行權.

?? 多個進程在搶這個資源,而其中一個進程如果有多個執行路徑,即多個線程,那么就有更高的幾率搶到CPU的執行權

JVM的啟動是單線程的還是多線程的?

? 是多線程的,啟動jvm是就相當于啟動了一個進程,接著該進程會創建一個主線程來調用main方法,而同時還有啟動其他的線程,比如說垃圾回收的線程.

兩種方式實現多線程,一種是繼承Thread類,一種是實現Runnable接口.以第一種為例:

package com.wang.reflect; class MyThread extends Thread{ @Override public void run() { for(int i=0;i<10;i++){ //獲取當前正在執行的線程的名稱,相當于this.getName(); System.out.println(Thread.currentThread().getName()+"::"+i); } } } public class TestReflect { public static void main(String[] args) throws Exception { MyThread mThread1=new MyThread(); MyThread mThread2=new MyThread(); //設置線程的名字,也可以直接通過帶參構造函數設置線程名稱 mThread1.setName("張無忌:"); mThread2.setName("趙敏:"); mThread1.start(); mThread2.start(); for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"::"+i); } } }

一般我們使用第二種方式實現多線程,實現Runnable接口的方式相比較繼承Thread類的方式有兩個好處:

??? 1.避免由于java單繼承帶來的局限性.

?? 2.適合多個相同程序的代碼去處理同一個資源的情況,把線程同程序的代碼,數據,有效分離,較好地體現了面向對象的思想.

線程調度:

線程有兩種調度模型:

??? 1.分式調度模型,所有的線程輪流使用CPU的使用權,平均分配每個線程占用的CPU時間片.

??? 2.搶占式調度模型,優先讓優先級高的線程先執行,如果優先級相同,那么隨機選擇一個線程,優先級高的線程獲得CPU的執行權的幾率大一些,并不是嚴格按照優先級由高到低執行.

java使用的是搶占式調度模型.

方法介紹:

獲取當前線程對象的優先級,默認優先級為5,范圍是1~10int? getPriority()
設置當前線程的優先級,范圍1~10?? void? setPriority()
在指定毫秒內讓正在運行的線程休眠(暫停執行)static void sleep(1000)
----------------------------------------------------------------------------------------
等待當前線程執行結束,該方法一般緊隨start()方法之后final void join()
暫停當前正在執行的對象,執行其他線程,(禮讓線程)static void yield()

將該線程標記為守護線程或用戶線程。

當正在運行的線程都是守護線程時,Java 虛擬機退出。

該方法必須在啟動線程前調用。

final void setDaemon(true)

看這張圖,來更好的理解守護線程:

假設現在有三個線程分別叫關羽,劉備,張飛.將關羽,張飛設置為守護線程,一旦劉備這個線程執行完畢(死掉),那么關羽,張飛也就沒有活著的意義了(不再執行,退出).

中斷線程,把線程狀態終止,并拋出一個InterruptedException??????? void interrupt()

線程的生命周期:

案例練習:

電影院賣票,假設有三個窗口同時賣票,共有100張票,用多線程模擬這個過程(要解決的關鍵問題是:線程同步).

package com.wang.reflect; class SellTicket implements Runnable { // 共享變量 private int tickets = 100; // 創建鎖對象 private Object obj = new Object(); @Override public void run() { while (true) { /** * 解決線程同步問題的 方案: * synchronized(鎖對象){ * //操作共享變量的代碼 * } * */ synchronized (obj) { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票"); } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } public class SellTicketDemo { public static void main(String[] args) { SellTicket st = new SellTicket(); Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); t1.start(); t2.start(); t3.start(); } }

打印結果如下:

synchronized是一個關鍵字.可以加在一段代碼外部,也可以放在一個方法前.它的鎖對象可以是任意對象,當然也可以寫成當前類的對象this.

  • 同步代碼塊的鎖對象:任意對象
  • 同步方法的鎖對象:當前對象this
  • 同步靜態方法的鎖對象:當前類的字節碼對象,類名.class;

?

java類庫中線程安全的類有:StringBuffer,HashTable,Vector.

注意Vector是線程安全的,但是當我們需要一個線程安全的集合的時候,我們一般也不用它,在Collections類中獲取線程安全的list集合的方法,假設我們現在需要獲得一個線程安全的List<String>集合,可以這樣寫:

List<String> list=Collections.synchronizedList(new ArrayList<String>());

?

???? 雖然說我們可以理解同步代碼塊和同步方法的鎖對象問題,但我們并沒有直接看到在哪兒加上鎖又在哪兒釋放鎖,為了更清晰的表達如何加鎖和釋放鎖,JDK1.5以后提供了一個新的鎖對象Lock.下面通過Lock鎖實現上述賣票的過程.

package com.wang.reflect; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class SellTicket implements Runnable { // 共享變量 private int tickets = 100; // Lock是一個接口,ReentrantLock是他的一個實現類 private Lock lock=new ReentrantLock(); @Override public void run() { while (true) { lock.lock();//加鎖 if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票"); } lock.unlock();//釋放鎖 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class SellTicketDemo { public static void main(String[] args) { SellTicket st = new SellTicket(); Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); t1.start(); t2.start(); t3.start(); } }

線程同步有兩個很明顯的弊:一是效率低,二是容易產生死鎖.

死鎖問題:

兩個或兩個以上的線程,在爭奪資源的過程中,發生的一種相互等待的過程.下面通過代碼演示死鎖問題的存在:

package com.wang.reflect; class DieLock extends Thread{ private boolean flag; public DieLock(boolean flag){ this.flag=flag; } public static final Object o1=new Object(); public static final Object o2=new Object(); @Override public void run() { if(flag){ synchronized(o1){ System.out.println("if o1"); synchronized (o2) { System.out.println("if o2"); } } }else{ synchronized (o2) { System.out.println("else o2"); synchronized (o1) { System.out.println("else o1"); } } } } } public class DieLockDemo { public static void main(String[] args) { DieLock dl1=new DieLock(true); DieLock dl2=new DieLock(false); dl1.start(); dl2.start(); } }

細讀代碼,可以發現,理想狀態下,應該會打印:

if o1

if o2

else o2

else o1

但是運行之后,發現打印結果大多為:

if o1???????????? 或者???? else o2

else o2??????????????????? if? o1

其實這里就發生了線程互相等待,也就是死鎖問題.

生產者-消費者模式描述:

package com.wang.reflect; //學生實體類作為共享資源 class Student{ String name;//姓名 int age;//年齡 boolean flag;//標記變量,判斷當前學生對象是否已創建賦值好 } //模擬生產者線程類 class SetStudent implements Runnable{ //共享資源s private Student s; private int x=0; public SetStudent(Student s) { this.s=s; } @Override public void run() { while(true){ synchronized (s) { if(s.flag){ try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(x%2==0){ s.name="郭靖"; s.age=24; }else{ s.name="黃蓉"; s.age=18; } x++; //生產完之后,將標記置為true,通知消費者來消費 s.flag=true; //喚醒線程 s.notify(); } } } } //模擬消費者線程類 class GetStudent implements Runnable{ //共享資源s private Student s; public GetStudent(Student s) { this.s=s; } @Override public void run() { while(true){ synchronized (s) { if(!s.flag){ try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(s.name+":::"+s.age); //消費完以后將標記之置于false,通知生產者來生產 s.flag=false; //喚醒線程 s.notify(); } } } } //測試類 public class StudentDemo { public static void main(String[] args) { Student s =new Student(); SetStudent ss=new SetStudent(s); GetStudent gs=new GetStudent(s); Thread t1=new Thread(ss, "生產者"); Thread t2=new Thread(gs, "消費者"); t1.start(); t2.start(); } }

在上面的代碼中,生產者就是代表對Student屬性進行賦值,消費者就是代表對Studnet屬性進行打印,代碼設置了等待喚醒機制.

上述代碼可以優化的,可以講生產者的賦值行為,和消費者的打印行為,封裝到Student類中,寫成兩個同步方法.實現這兩個功能.代碼如下:

package com.wang.reflect; //學生實體類作為共享資源 class Student { private String name;// 姓名 private int age;// 年齡 boolean flag;// 標記變量,判斷當前學生對象是否已創建賦值好 public synchronized void set(String name, int age) { if (this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name; this.age = age; this.flag = true; this.notify(); } public synchronized void get() { if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(name + ":::" + age); this.flag = false; this.notify(); } } // 模擬生產者線程類 class SetStudent implements Runnable { // 共享資源s private Student s; private int x = 0; public SetStudent(Student s) { this.s = s; } @Override public void run() { while (true) { if (x % 2 == 0) { s.set("郭靖", 27); } else { s.set("黃蓉", 18); } x++; } } } // 模擬消費者線程類 class GetStudent implements Runnable { // 共享資源s private Student s; public GetStudent(Student s) { this.s = s; } @Override public void run() { while (true) { s.get(); } } } // 測試類 public class StudentDemo { public static void main(String[] args) { Student s = new Student(); SetStudent ss = new SetStudent(s); GetStudent gs = new GetStudent(s); Thread t1 = new Thread(ss, "生產者"); Thread t2 = new Thread(gs, "消費者"); t1.start(); t2.start(); } }

轉載于:https://www.cnblogs.com/fingerboy/p/5347314.html

總結

以上是生活随笔為你收集整理的java多线程--多线程基础小结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。