Java作為一種跨平台的編程語言,其多線程的特性使得它在並發處理的場景下十分重要。本文將從多個方面對Java多線程的實現方法進行闡述,包括線程的創建、Thread和Runnable介面、線程同步、線程池以及線程安全。
一、線程的創建
線程的創建是指創建一個獨立的執行單元,切換到該執行單元可實現多任務並發執行。Java中線程的創建主要有兩種方式:
1. 繼承Thread類
public class MyThread extends Thread { public void run() { // 實現線程體代碼 } } // 創建線程 MyThread myThread = new MyThread(); myThread.start();
通過繼承Thread類並重寫run()方法實現線程體,然後創建該類的實例並調用start()方法啟動線程。
2. 實現Runnable介面
public class MyRunnable implements Runnable { public void run() { // 實現線程體代碼 } } // 創建線程 Thread thread = new Thread(new MyRunnable()); thread.start();
通過實現Runnable介面並實現run()方法實現線程體,然後創建Thread類的實例並將該介面實例化作為參數傳入,最後調用start()方法啟動線程。
二、Thread和Runnable介面
Thread類和Runnable介面是Java中定義線程的兩個基本方式,二者的區別主要在於:
1. 繼承Thread類
優點:可以直接調用Thread類的方法,簡單直接。
缺點:由於Java不支持多重繼承,因此如果繼承Thread類將會佔用一個類的繼承關係。
2. 實現Runnable介面
優點:可以避免單繼承的限制,使得程序的擴展性更好。
缺點:不能直接調用Thread類的方法,需要創建Thread實例並將Runnable實例作為參數傳入才能啟動線程。
三、線程同步
多線程在執行時,如若對共享資源進行讀取或修改,會出現數據不一致或者數據安全問題,為了避免這類問題,Java提供了synchronized關鍵字鎖定代碼塊、實例方法和類方法。在Java使用synchronized關鍵字實現線程同步的方式有如下幾種:
1. 同步代碼塊
synchronized (object) { // 訪問共享資源代碼 }
其中object為鎖對象,同步代碼塊只能被同一把鎖的線程訪問,僅在執行完同步代碼塊時才釋放鎖。
2. 同步實例方法
public synchronized void method() { // 訪問共享資源代碼 }
對實例方法加synchronized關鍵字可以實現對整個方法的同步,同一時刻只能有一個線程訪問該方法,其他線程需要等待。
3. 同步類方法
public static synchronized void method() { // 訪問共享資源代碼 }
對類方法加synchronized關鍵字可以實現對整個類的同步,同一時刻只能有一個線程訪問該類的類方法,其他線程需要等待。
四、線程池
在Java中,線程池是用來管理線程的一種機制,它可以減少線程創建、上下文切換的開銷,提高系統的運行效果。
Java提供了Executor和ExecutorService介面作為線程池的操作類,常用的線程池實現類有ThreadPoolExecutor、ScheduledThreadPoolExecutor等。
1. ThreadPoolExecutor
ThreadPoolExecutor是Java中線程池的基本實現,其構造方法參數較多:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
其中,corePoolSize指定了線程池的核心線程數量,maximumPoolSize指定了最大線程數量,當工作隊列滿時並且當前的線程數小於最大線程數時,線程池會新建線程。keepAliveTime和unit參數指定了空閑線程存活的時間,workQueue為任務隊列,用於存放還沒有執行的任務。threadFactory用於創建新線程,handler則是當線程池滿了並且阻塞隊列也滿了時採取的拒絕處理策略。
2. ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor繼承自ThreadPoolExecutor,是一個可以周期性執行任務的線程池,常用於定時器等場景。
ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler)
其中,corePoolSize和threadFactory參數與ThreadPoolExecutor類似,handler為拒絕策略。
五、線程安全
Java中線程安全是指多個線程同時執行某個方法或者代碼塊時,不會產生數據衝突、數據覆蓋等安全問題。Java提供了多種線程安全的機制,其中常用的有volatile、synchronized關鍵字和Atomic包等。
1. volatile關鍵字
volatile關鍵字可以保證變數的可見性和禁止指令重排,但不具備互斥性,因此不能保證原子性。
public class VolatileTest { public volatile int count = 0; public void increase() { count++; } public static void main(String[] args) throws InterruptedException { final VolatileTest test = new VolatileTest(); for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { public void run() { test.increase(); } }).start(); } Thread.sleep(1000); System.out.println(test.count); } }
2. synchronized關鍵字
synchronized關鍵字可以保證臨界區代碼的原子性和可見性,但會降低程序的並發性。
public class SynchronizedTest { public int count = 0; public synchronized void increase() { count++; } public static void main(String[] args) throws InterruptedException { final SynchronizedTest test = new SynchronizedTest(); for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { public void run() { test.increase(); } }).start(); } Thread.sleep(1000); System.out.println(test.count); } }
3. Atomic包
Atomic包提供了一系列的原子性操作類,包括AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference等,可以保證變數的原子性和可見性。
public class AtomicTest { public AtomicInteger count = new AtomicInteger(0); public void increase() { count.incrementAndGet(); } public static void main(String[] args) throws InterruptedException { final AtomicTest test = new AtomicTest(); for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { public void run() { test.increase(); } }).start(); } Thread.sleep(1000); System.out.println(test.count); } }
總結
在多線程編程中,線程的創建、Thread和Runnable介面、線程同步、線程池以及線程安全是相對核心和常用的知識點。使用好這些多線程編程的基礎知識,可以十分高效地完成開發任務,並在高並發場景下保證程序的運行效率和數據安全。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/194567.html