Java多執行緒基本使用
多執行緒是Java中不可避免的一個重要主體,下面小編為大家介紹了Java多執行緒基本使用,希望能幫到大家!
一、概念
1.程序
1.1程序:是一個正在進行中的程式,每一個程序執行都有一個執行順序,該順序是一個執行路徑,或者叫一個控制單元。
1.2執行緒:就是程序中一個獨立的控制單元,執行緒在控制著程序的執行,一個程序中至少有一個執行緒。
1.3舉例java VM:
Java VM啟動的時候會有一個程序,該程序中至少有一個執行緒在負責java程式的執行,而且這個執行緒執行的程式碼存在於main方法中,該執行緒稱之為主執行緒。擴充套件:其實更細節說明jvm,jvm啟動不止一個執行緒,還有負責垃圾回收機制的執行緒
2.多執行緒存在的意義:提高執行效率
二、多執行緒的建立
1.多執行緒建立的第一種方式,繼承Thread類
1.1定義類繼承Thread,複寫Thread類中的run方法是為了將自定義的程式碼儲存到run方法中,讓執行緒執行
1.2呼叫執行緒的start方法,該方法有兩個作用:啟動執行緒,呼叫run方法
1.3多執行緒執行的時候,執行結果每一次都不同,因為多個執行緒都獲取cpu的執行權,cpu執行到誰,誰就執行,明確一點,在某一個時刻,只能有一個程式在執行。(多核除外),cpu在做著快速的切換,以到達看上去是同時執行的效果。我們可以形象把多執行緒的執行行為在互搶cpu的執行權。這就是多執行緒的一個特性,隨機性。誰搶到,誰執行,至於執行多久,cpu說了算。
public class Demo extends Thread{
public void run(){
for (int x = 0; x < 60; x++) {
tln(ame()+"demo run---"+x);
}
}
public static void main(String[] args) {
Demo d=new Demo();//建立一個執行緒
t();//開啟執行緒,並執行該執行緒的run方法
(); //僅僅是物件呼叫方法,而執行緒建立了但並沒有執行
for (int x = 0; x < 60; x++) {
tln("Hello World---"+x);
}
}
}
2 建立多執行緒的第二種方式,步驟:
2.1定義類實現Runnable介面
2.2覆蓋Runnable介面中的run方法:將執行緒要執行的程式碼存放到run方法中
2.3.通過Thread類建立執行緒物件
2.4.將Runnable介面的子類物件作為實際引數傳遞給Thread類的建構函式
為什麼要將Runnable介面的.子類物件傳遞給Thread的建構函式:因為自定義的run方法所屬的物件是Runnable介面的子類物件,所以要讓執行緒去執行指定物件的run方法,就必須明確該run方法的所屬物件
2.5.呼叫Thread類的start方法開啟執行緒並呼叫Runnable介面子類的方法
/*
* 需求:簡易買票程式,多個視窗同時賣票
*/
public class Ticket implements Runnable {
private static int tick = 100;
Object obj = new Object();
boolean flag=true;
public void run() {
if(flag){
while (true) {
synchronized (s) {
if (tick > 0) {
tln(entThread()ame()
+ "code:" + tick--);
}
}
}
}else{
while(true){
show();
}
}
}
public static synchronized void show() {
if (tick > 0) {
tln(entThread()ame() + "show:"
+ tick--);
}
}
}
class ThisLockDemo {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread t1 = new Thread(t);
try {
p(10);
} catch (Exception e) {
// TODO: handle exception
}
=false;
Thread t2 = new Thread(t);
//Thread t3 = new Thread(t);
//Thread t4 = new Thread(t);
t();
t();
//t();
//t();
}
}
3.實現方式和繼承方式有什麼區別
3.1.實現方式避免了單繼承的侷限性,在定義執行緒時建議使用實現方式
3.2.繼承Thread類:執行緒程式碼存放在Thread子類run方法中
3.3.實現Runnable:執行緒程式碼存放在介面的子類run方法中
4.多執行緒-run和start的特點
4.1為什麼要覆蓋run方法呢:
Thread類用於描述執行緒,該類定義了一個功能,用於儲存執行緒要執行的程式碼,該儲存功能就是run方法,也就是說該Thread類中的run方法,用於儲存執行緒要執行的程式碼
5.多執行緒執行狀態
建立執行緒-執行---sleep()/wait()--凍結---notify()---喚醒
建立執行緒-執行---stop()—消亡
建立執行緒-執行---沒搶到cpu執行權—臨時凍結
6.獲取執行緒物件及其名稱
6.1.執行緒都有自己預設的名稱,編號從0開始
ic Thread currentThread():獲取當前執行緒物件
ame():獲取執行緒名稱
6.4.設定執行緒名稱:setName()或者使用建構函式
public class Test extends Thread{
Test(String name){
super(name);
}
public void run(){
for (int x = 0; x < 60; x++) {
tln((entThread()==this)+"..."+ame()+" run..."+x);
}
}
}
class ThreadTest{
public static void main(String[] args) {
Test t1=new Test("one---");
Test t2=new Test("two+++");
t();
t();
();
();
for (int x = 0; x < 60; x++) {
tln("main----"+x);
}
}
}
三、多執行緒的安全問題
1.多執行緒出現安全問題的原因:
1.1.當多條語句在操作同一個執行緒共享資料時,一個執行緒對多條語句只執行了一部分,還沒有執行完,另一個執行緒參與進來執行,導致共享資料的錯誤
1.2.解決辦法:對多條操作共享資料的語句,只能讓一個執行緒都執行完,在執行過程中,其他執行緒不可以參與執行
對於多執行緒的安全問題提供了專業的解決方式,就是同步程式碼塊:
Synchronized(物件){需要被同步的程式碼},物件如同鎖,持有鎖的執行緒可以在同步中執行,沒有持有鎖的執行緒即使獲取cpu執行權,也進不去,因為沒有獲取鎖
2.同步的前提:
2.1.必須要有2個或者2個以上執行緒
2.2.必須是多個執行緒使用同一個鎖
2.3.好處是解決了多執行緒的安全問題
2.4.弊端是多個執行緒需要判斷鎖,較消耗資源
2.5.同步函式
定義同步函式,在方法錢用synchronized修飾即可
/*
* 需求:
* 銀行有一個金庫,有兩個儲戶分別存300元,每次存100元,存3次
* 目的:該程式是否有安全問題,如果有,如何解決
* 如何找問題:
* 1.明確哪些程式碼是多執行緒程式碼
* 2.明確共享資料
* 3.明確多執行緒程式碼中哪些語句是操作共享資料的
*/
public class Bank {
private int sum;
Object obj = new Object();
//定義同步函式,在方法錢用synchronized修飾即可
public synchronized void add(int n) {
//synchronized (obj) {
sumsum = sum + n;
try {
p(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
tStackTrace();
}
tln("sum=" + sum);
//}
}
}
class Cus implements Runnable {
private Bank b = new Bank();
public void run() {
for (int x = 0; x < 3; x++) {
(100);
}
}
}
class BankDemo {
public static void main(String[] args) {
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t();
t();
}
}
6.同步的鎖
6.1函式需要被物件呼叫,那麼函式都有一個所屬物件引用,就是this.,所以同步函式使用的鎖是this
6.2.靜態函式的鎖是class物件
靜態進記憶體時,記憶體中沒有本類物件,但是一定有該類對應的位元組碼檔案物件,類名s,該物件的型別是Class
6.3.靜態的同步方法,使用的鎖是該方法所在類的位元組碼檔案物件,類名s
/*
* 需求:簡??買票程式,多個視窗同時賣票
*/
public class Ticket implements Runnable {
private static int tick = 100;
Object obj = new Object();
boolean flag=true;
public void run() {
if(flag){
while (true) {
synchronized (s) {
if (tick > 0) {
tln(entThread()ame()
+ "code:" + tick--);
}
}
}
}else{
while(true){
show();
}
}
}
public static synchronized void show() {
if (tick > 0) {
tln(entThread()ame() + "show:"
+ tick--);
}
}
}
class ThisLockDemo {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread t1 = new Thread(t);
try {
p(10);
} catch (Exception e) {
// TODO: handle exception
}
=false;
Thread t2 = new Thread(t);
//Thread t3 = new Thread(t);
//Thread t4 = new Thread(t);
t();
t();
//t();
//t();
}
}
7.多執行緒,單例模式-懶漢式
懶漢式與餓漢式的區別:懶漢式能延遲例項的載入,如果多執行緒訪問時,懶漢式會出現安全問題,可以使用同步來解決,用同步函式和同步程式碼都可以,但是比較低效,用雙重判斷的形式能解決低效的問題,加同步的時候使用的鎖是該類鎖屬的位元組碼檔案物件
8.多執行緒-死鎖
同步中巢狀同步會出現死鎖