1. 程式人生 > >java 多執行緒介紹

java 多執行緒介紹

多執行緒
  • 什麼是執行緒
    • 執行緒是程式執行的一條路徑, 一個程序中可以包含多條執行緒
    • 多執行緒併發執行可以提高程式的效率, 可以同時完成多項工作(cpu不斷切換任務)當然多核cpu是不一樣的
多執行緒並行和併發的區別
  • 並行就是兩個任務同時執行,就是甲任務進行的同時,乙任務也在進行。(需要多核CPU)
  • 併發是指兩個任務都請求執行,而處理器只能按受一個任務,就把這兩個任務安排輪流進行,由於時間間隔較短,使人感覺兩個任務都在執行。
    比如:
    JVM的啟動是多執行緒的嗎
    JVM啟動至少啟動了垃圾回收執行緒和主執行緒,所以是多執行緒的。
多執行緒程式實現的兩種方式
  • 繼承Thread
    • 定義類繼承Thread
    • 重寫run方法
    • 把新執行緒要做的事寫在run方法中
    • 建立執行緒物件
    • 開啟新執行緒, 內部會自動執行run方法
			public class Demo2_Thread {
				public static void main(String[] args) {
					MyThread mt = new MyThread();							
					mt.start();												
					for(int
i = 0; i < 1000; i++) { System.out.println("b"); } } } class MyThread extends Thread { public void run() { for(int i = 0; i < 1000; i++) { System.out.println("a"); } } }
  • 實現Runnable(方法二)
    • 定義類實現Runnable介面
    • 實現run方法
    • 把新執行緒要做的事寫在run方法中
    • 建立自定義的Runnable的子類物件
    • 建立Thread物件, 傳入Runnable
    • 呼叫start()開啟新執行緒, 內部會自動呼叫Runnable的run()方法
			public class Demo3_Runnable {
				public static void main(String[] args) {
					MyRunnable mr = new MyRunnable();						
					Thread t = new Thread(mr);								
					t.start();												
					for(int i = 0; i < 1000; i++) {
						System.out.println("b");
					}
				}
			}
			class MyRunnable implements Runnable {							
				@Override
				public void run() {											
					for(int i = 0; i < 1000; i++) {							
						System.out.println("a");
					}
				}	
			}

Runnable 底層也是依賴 Thread的

兩種方式的區別
  • 繼承Thread : 由於子類重寫了Thread類的run(), 當呼叫start()時, 直接找子類的run()方法

  • 實現Runnable : 建構函式中傳入了Runnable的引用, 成員變數記住了它, start()呼叫run()方法時內部判斷成員變數Runnable的引用是否為空, 不為空編譯時看的是Runnable的run(),執行時執行的是子類的run()方法

  • 繼承Thread

    • 好處是:可以直接使用Thread類中的方法,程式碼簡單
    • 弊端是:如果已經有了父類,就不能用這種方法
  • 實現Runnable介面

    • 好處是:即使自己定義的執行緒類有了父類也沒關係,因為有了父類也可以實現介面,而且介面是可以多實現的
    • 弊端是:不能直接使用Thread中的方法需要先獲取到執行緒物件後,才能得到Thread的方法,程式碼複雜
匿名內部類實現執行緒的兩種方式

繼承Thread類

		new Thread() {													
			public void run() {											
				for(int i = 0; i < 1000; i++) {							
					System.out.println("a");
				}
			}
		}.start();

實現Runnable介面

		new Thread(new Runnable(){										
			public void run() {											
				for(int i = 0; i < 1000; i++) {							
					System.out.println("b");
				}
			}
		}).start(); 
獲取名字和設定名字
  • 獲取名字
    • 通過getName()方法獲取執行緒物件的名字
  • 設定名字
    • 通過建構函式可以傳入String型別的名字
		new Thread("xxx") {
				public void run() {
					for(int i = 0; i < 1000; i++) {
						System.out.println(this.getName() + "***");
					}
				}
			}.start();
			
			new Thread("yyy") {
				public void run() {
					for(int i = 0; i < 1000; i++) {
						System.out.println(this.getName() + "++++");
					}
				}
			}.start(); 

通過setName(String)方法可以設定執行緒物件的名字

	
			Thread t1 = new Thread() {
				public void run() {
					for(int i = 0; i < 1000; i++) {
						System.out.println(this.getName() + "*****");
					}
				}
			};
			
			Thread t2 = new Thread() {
				public void run() {
					for(int i = 0; i < 1000; i++) {
						System.out.println(this.getName() + "+++++");
					}
				}
			};
			t1.setName("xixi");
			t2.setName("哈哈");
			
			t1.start();
			t2.start();

獲取當前執行緒的物件

Thread.currentThread(), 主執行緒也可以獲取

	new Thread(new Runnable() {
			public void run() {
				for(int i = 0; i < 1000; i++) {
					System.out.println(Thread.currentThread().getName() + "*****");
				}
			}
		}).start();
			
			new Thread(new Runnable() {
				public void run() {
					for(int i = 0; i < 1000; i++) {
						System.out.println(Thread.currentThread().getName() + "++++");
					}
				}
			}).start();
			Thread.currentThread().setName("我是主執行緒");					
			System.out.println(Thread.currentThread().getName());	
休眠執行緒
  • Thread.sleep(毫秒,納秒), 控制當前執行緒休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 * 1000 * 1000納秒 1000000000
守護執行緒
  • setDaemon(), 設定一個執行緒為守護執行緒, 該執行緒不會單獨執行, 當其他非守護執行緒都執行結束後, 自動退出
		Thread t1 = new Thread() {
				public void run() {
					for(int i = 0; i < 50; i++) {
						System.out.println(getName() + "****");
						try {
							Thread.sleep(10);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			};
			
			Thread t2 = new Thread() {
				public void run() {
					for(int i = 0; i < 5; i++) {
						System.out.println(getName() + "++++");
						try {
							Thread.sleep(10);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			};
			
			t1.setDaemon(true);						//將t1設定為守護執行緒
			
			t1.start();
			t2.start();
加入執行緒
  • join(), 當前執行緒暫停, 等待指定的執行緒執行結束後, 當前執行緒再繼續
  • join(int), 可以等待指定的毫秒之後繼續
			final Thread t1 = new Thread() {
				public void run() {
					for(int i = 0; i < 50; i++) {
						System.out.println(getName() + "*****");
						try {
							Thread.sleep(10);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			};
			
			Thread t2 = new Thread() {
				public void run() {
					for(int i = 0; i < 50; i++) {
						if(i == 2) {
							try {					
								t1.join(30);					
								Thread.sleep(10);
							} catch (InterruptedException e) {
								
								e.printStackTrace();
							}
						}
						System.out.println(getName() + "+++++");
					}
				}
			};
			t1.start();
			t2.start();
禮讓執行緒和設定執行緒的優先順序
  • yield()讓出cpu
  • setPriority()設定執行緒的優先順序
同步程式碼塊
  • 什麼情況下需要同步
    • 當多執行緒併發, 有多段程式碼同時執行時, 我們希望某一段程式碼執行的過程中CPU不要切換到其他執行緒工作. 這時就需要同步.
    • 如果兩段程式碼是同步的, 那麼同一時間只能執行一段, 在一段程式碼沒執行結束之前, 不會執行另外一段程式碼.
  • 同步程式碼塊
    • 使用synchronized關鍵字加上一個鎖物件來定義一段程式碼, 這就叫同步程式碼塊
    • 多個同步程式碼塊如果使用相同的鎖物件, 那麼他們就是同步的
public static void main(String[] args) {
		final Printer p = new Printer();
		
		new Thread() {
			public void run() {
				while(true) {
					p.print1();
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					p.print2();
				}
			}
		}.start();
	}

}

	class Printer {
				Demo d = new Demo();
				public static void print1() {
					synchronized(d){				
		//鎖物件可以是任意物件,但是被鎖的程式碼需要保證是同一把鎖,不能用匿名物件
						System.out.print("A");
						System.out.print("B");
						System.out.print("C");
						System.out.print("D");
						System.out.print("\r\n");
					}
				}
	
				public static void print2() {	
					synchronized(d){	
						System.out.print("1");
						System.out.print("2");
						System.out.print("3");
						System.out.print("4");
						System.out.print("\r\n");
					}
				}
			}
同步方法
  • 使用synchronized關鍵字修飾一個方法, 該方法中所有的程式碼都是同步的
	class Printer {
			public static void print1() {
				synchronized(Printer.class){			
			//鎖物件可以是任意物件,但是被鎖的程式碼需要保證是同一把鎖,不能用匿名物件
						System.out.print("A");
						System.out.print("B");
						System.out.print("C");
						System.out.print("D");
					System.out.print("\r\n");
				}
			}
			/*
			 * 非靜態同步函式的鎖是:this
			 * 靜態的同步函式的鎖是:位元組碼物件
			 */
			public static synchronized void print2() {	
					System.out.print("1");
					System.out.print("2");
					System.out.print("3");
					System.out.print("4");
				System.out.print("\r\n");
			}
		}

單例設計模式
  • 單例設計模式:保證類在記憶體中只有一個物件。
  • 如何保證類在記憶體中只有一個物件呢?
    • (1)控制類的建立,不讓其他類來建立本類的物件。private
    • (2)在本類中定義一個本類的物件。Singleton s;
    • (3)提供公共的訪問方式。 public static Singleton getInstance(){return s}
  • 單例寫法兩種:
    • (1)餓漢式 開發用這種方式。
	class Singleton {
				//1,私有建構函式
				private Singleton(){}
				//2,建立本類物件
				private static Singleton s = new Singleton();
				//3,對外提供公共的訪問方法
				public static Singleton getInstance() {
					return s;
				}
				
				public static void print() {
					System.out.println("11111111111");
				}
			}
  • (2)懶漢式 面試寫這種方式。多執行緒的問題?
		//懶漢式,單例的延遲載入模式
			class Singleton {
				//1,私有建構函式
				private Singleton(){}
				//2,宣告一個本類的引用
				private static Singleton s;
				//3,對外提供公共的訪問方法
				public static Singleton getInstance() {
					if(s == null)
						//執行緒1,執行緒2 執行緒不安全
						s = new Singleton();
					return s;
				}
			}

餓漢和懶漢的區別:
1.餓漢空間換時間,懶漢相反
2.懶漢執行緒不安全

  • (3)第三種格式
			class Singleton {
				private Singleton() {}
			
				public static final Singleton s = new Singleton();
				//final是最終的意思,被final修飾的變數不可以被更改
			}

Runtime類是一個單例類

Timer

它是java的定時器,可以定時執行一個任務,或者間隔一段時間重複執行一個任務
schedule()方法

			public class DTimer {
				public static void main(String[] args) throws InterruptedException {
					Timer t = new Timer();
					t.schedule(new MyTimerTask(), new Date(118,12,7,10,54,20),5000);
					//第一個引數 是一個繼承TimerTask類的類 物件 繼承要重寫run()方法 ,也就是要多執行緒執行內容
					//第二個引數是Date物件
					//第三個引數是間隔時間
				}
			}
			class MyTimerTask extends TimerTask {
				public void run() {
					System.out.println("該敲程式碼了");
				}
				
			}
等待執行緒和喚醒執行緒

物件.wait()讓一個執行緒等待
物件.notify()任意喚醒一個執行緒
物件.notify()喚醒所有等待執行緒

注意點:

  • 1,在同步程式碼塊中,用哪個物件鎖,就用哪個物件呼叫wait方法
  • 2,為什麼wait方法和notify方法定義在Object這類中?
    因為鎖物件可以是任意物件,Object是所有的類的基類,所以wait方法和notify方法需要定義在Object這個類中
  • 3,sleep方法和wait方法的區別?
    a,sleep方法必須傳入引數,引數就是時間,時間到了自動醒來
    wait方法可以傳入引數也可以不傳入引數,傳入引數就是在引數的時間結束後等待,不傳入引數就是直接等待
    b,sleep方法在同步函式或同步程式碼塊中,不釋放鎖,睡著了也抱著鎖睡
    wait方法在同步函式或者同步程式碼塊中,釋放鎖
多個執行緒的執行問題(互斥鎖運用)
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Demo3_ReentrantLock {
	public static void main(String[] args) {
		final Printer3 p = new Printer3();
		
		new Thread() {
			public 
            
           

相關推薦

java 執行介紹

多執行緒 什麼是執行緒 執行緒是程式執行的一條路徑, 一個程序中可以包含多條執行緒 多執行緒併發執行可以提高程式的效率, 可以同時完成多項工作(cpu不斷切換任務)當然多核cpu是不一樣的 多執行緒並行和併發的區別

java定時器類Timer和執行介紹及例項

任務要求: 完成一個java application應用程式,使用定時器程式設計,在實時顯示當前時間,每1秒時鐘內容更新一次。 完成一個java application應用程式,在應用程式主程序中新開一個執行緒,此執行緒進行死迴圈,每1秒被啟用一次,啟用時即在

Java併發性和執行介紹》-Java TheadLocal

原文連結 作者:Jakob Jenkov   檢視全部文章 Java中的ThreadLocal類可以讓你建立的變數只被同一個執行緒進行讀和寫操作。因此,儘管有兩個執行緒同時執行一段相同的程式碼,而且這段程式碼又有一個指向同一個ThreadLocal變數的引用,但是這兩個執行緒依然不能看到彼此的

Java併發性和執行介紹目錄

ThreadPoolExecutor.addIfUnderCorePoolSize(Runnable firstTask) { Thread t = null; final ReentrantLock mainLock = this.mainLock; ma

Java併發性和執行介紹

作者:Jakob Jenkov 譯者:Simon-SZ  校對:方騰飛 在過去單CPU時代,單任務在一個時間點只能執行單一程式。之後發展到多工階段,計算機能在同一時間點並行執行多工或多程序。雖然並不是真正意義上的“同一時間點”,而是多個任務或程序共享一個CPU,並交由作業系統來完成多工間對C

Java執行程式設計-(3)-執行本地ThreadLocal的介紹與使用

原文出自 : https://blog.csdn.net/xlgen157387/article/details/78114278 ThreadLocal簡介 我們通過上兩篇的學習,我們已經知道了變數值的共享可以使用public static變數的形式,所有的執行緒都使

Java執行(五)、執行其他知識簡要介紹

一、執行緒組 [java]  view plain  copy /**   * A thread gr

三、JAVA執行:Thread API詳細介紹 (sleep、Interrupt、Join、TimeUnit、yield、interrupted、執行優先順序 )

 本章深入分析了Thread的所有API,熟練掌握Thread的API是學好Thread的前提。   執行緒sleep sleep是一個靜態方法,一共有兩個過載方法,一個需要傳入毫秒數,另一個既要傳入毫秒數又要傳入納秒數。   sleep方法介紹

Java執行--執行介紹

為什麼會出現執行緒池?思考執行緒池問題時,我總是會和資料庫連線池聯想到一起,我個人覺得它們兩者的核心思想有很大的相像之處,它們都是利用了一種"池化"的思想,目的都是為了減少連線的建立和銷燬.  在多執行

java執行執行的基本介紹

程序和執行緒:     程序是程式的一次動態執行過程,經歷了從程式碼的載入、執行到執行完畢的一個完整的過程,這個過程也是程序本身從產生、發展到最終消亡的過程。     多執行緒是實現併發機制的一種有效手段。程序和執行緒一樣,都是實現併發的一個基本單位。 java實現多執行

java執行之守護執行Daemon()和Join()介紹

最近看了些多執行緒相關的同樣的避免忘了:我們先模擬一個需求,在http請求的時候我們都會發心跳包,就會一遍又一遍的去檢查心跳是否存在,但是當這個請求不用的時候我們採取什麼方式來把它關閉掉呢?因為Stop的方法我們已經被java淘汰掉了.這時候我們可以拿守護執行緒來做著件事:p

Java併發性和執行介紹、優缺點

在過去單核CPU時代,單任務在一個時間點只能執行單一程式。之後發展到多工階段,計算機能在同一時間點並行執行多工或多程序。雖然並不是真正意義上的“同一時間點”,而是多個任務或程序共享一個CPU,並交由

java執行總結-同步容器與併發容器的對比與介紹

目錄 1 容器集簡單介紹 2 同步容器 3 併發容器 4 案例講解 4.1 Map/Set 4.2 List 4.3 Queue 4.3.1 C

Java執行實現電影院售票案例

某電影院目前正在上映賀歲大片,共有100張票,而它有3個售票視窗,請設計一個程式模擬該電影院售票。 定義Sell類實現Runnable介面,很好的解決了單繼承共享資源問題 public class Sell implements Runnable { // 定義100張票,三個售票

java執行物件鎖、類鎖、同步機制詳解

1.在java多執行緒程式設計中物件鎖、類鎖、同步機制synchronized詳解:     物件鎖:在java中每個物件都有一個唯一的鎖,物件鎖用於物件例項方法或者一個物件例項上面的。     類鎖:是用於一個類靜態方法或者class物件的,一個

Java 執行實現死鎖場景

簡述: 《Java 程式設計思想》  P718 ~ P722 模擬死鎖的場景, 三個人 三根筷子,每個人需要拿到身邊的兩根筷子才能開始吃飯 出現死鎖的場景是,三個人都拿到了右邊的筷子,但是由於筷子都被搶佔,均無法獲得左邊的筷子 Chopstick.java

Java 執行 join和interrupt 方法

簡述: 使用Java多執行緒中join和interrupt函式 《Java程式設計思想》 P669 ~ P670 一個執行緒可以再其他執行緒上呼叫join()方法,其效果是等待一段時間直到第二個執行緒結束才繼續執行。 如果某個執行緒在另一個執行緒t上呼叫t.join(), 此

Java 執行 CountDownLatch 試用

簡述: 使用Java多執行緒的庫,包括 ExecutorService執行緒池, CountDownLatch執行緒執行控制(知道所有啟動的執行緒呼叫完成後,函式才會繼續執行) package test.anialy.multithread; import java.ut

Java執行中Synchronized簡介和Static Synchronized的區別

在進行Java開發時,多執行緒的開發是經常會使用的。首先會問一個小問題啊,在Java中有幾種方法可以建立一個執行緒? 我給的答案是3種。(如果還有其他的請留言告訴我哈。) 1、建立直接繼承自Thread類建立執行緒子類。   步驟如下:a 定義一個子類,同時

Java執行學習與總結(Join)

join()方法的用法: join()是主執行緒 等待子執行緒的終止。也就是在子執行緒呼叫了 join() 方法後面的程式碼,只有等到子執行緒結束了才能執行。 例子如下: Java程式碼 p