Java中的執行緒同步詳解

省赚客开发者团队發表於2024-07-13

Java中的執行緒同步詳解

大家好,我是微賺淘客系統3.0的小編,是個冬天不穿秋褲,天冷也要風度的程式猿!

在多執行緒程式設計中,執行緒同步是一個非常重要的話題。執行緒同步的目的是為了保證多個執行緒訪問共享資源時,能夠避免資料的不一致性和競爭條件。Java 提供了多種機制來實現執行緒同步,包括 synchronized 關鍵字、顯式鎖 (ReentrantLock)、訊號量 (Semaphore)、讀寫鎖 (ReadWriteLock) 等。本文將詳細介紹 Java 中的執行緒同步機制,涵蓋基本概念、常用方法和具體程式碼示例。

一、基本概念

執行緒同步是指協調多個執行緒對共享資源的訪問,以保證資料的一致性和正確性。在沒有同步的情況下,多個執行緒同時訪問和修改同一個共享資源,可能會導致資料的不一致性和難以預測的錯誤。

二、synchronized 關鍵字

synchronized 是 Java 提供的最基本的執行緒同步機制。它可以用於方法和程式碼塊,確保在同一時刻只有一個執行緒可以執行被 synchronized 修飾的方法或程式碼塊。

1. 同步方法

同步方法是指在方法宣告中使用 synchronized 關鍵字。

package cn.juwatech.threads;

public class SynchronizedMethodExample {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }

    public static void main(String[] args) {
        SynchronizedMethodExample example = new SynchronizedMethodExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

2. 同步程式碼塊

同步程式碼塊是指在程式碼塊中使用 synchronized 關鍵字。

package cn.juwatech.threads;

public class SynchronizedBlockExample {
    private final Object lock = new Object();
    private int count = 0;

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }

    public static void main(String[] args) {
        SynchronizedBlockExample example = new SynchronizedBlockExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

三、顯式鎖 (ReentrantLock)

ReentrantLock 是 Java 提供的顯式鎖,功能比 synchronized 更加豐富。它提供了更高的靈活性,可以顯式地獲取和釋放鎖,並且支援公平鎖和非公平鎖。

package cn.juwatech.threads;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private final Lock lock = new ReentrantLock();
    private int count = 0;

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLockExample example = new ReentrantLockExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

四、訊號量 (Semaphore)

Semaphore 是一種計數訊號量,用於控制同時訪問特定資源的執行緒數量。它可以用於實現資源池、限流等功能。

package cn.juwatech.threads;

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private final Semaphore semaphore = new Semaphore(3);

    public void accessResource(int threadId) {
        try {
            semaphore.acquire();
            System.out.println("Thread " + threadId + " is accessing resource...");
            Thread.sleep(2000);
            System.out.println("Thread " + threadId + " is releasing resource.");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            semaphore.release();
        }
    }

    public static void main(String[] args) {
        SemaphoreExample example = new SemaphoreExample();

        for (int i = 1; i <= 10; i++) {
            int threadId = i;
            new Thread(() -> example.accessResource(threadId)).start();
        }
    }
}

五、讀寫鎖 (ReadWriteLock)

ReadWriteLock 是一種讀寫鎖,用於區分讀操作和寫操作。它允許多個讀操作併發進行,但寫操作是互斥的。

package cn.juwatech.threads;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private int count = 0;

    public void increment() {
        rwLock.writeLock().lock();
        try {
            count++;
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public int getCount() {
        rwLock.readLock().lock();
        try {
            return count;
        } finally {
            rwLock.readLock().unlock();
        }
    }

    public static void main(String[] args) {
        ReadWriteLockExample example = new ReadWriteLockExample();

        Runnable writerTask = () -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        };

        Runnable readerTask = () -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("Count: " + example.getCount());
            }
        };

        Thread writerThread = new Thread(writerTask);
        Thread readerThread1 = new Thread(readerTask);
        Thread readerThread2 = new Thread(readerTask);

        writerThread.start();
        readerThread1.start();
        readerThread2.start();

        try {
            writerThread.join();
            readerThread1.join();
            readerThread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

六、執行緒同步的最佳實踐

  1. 選擇合適的同步機制:根據具體需求選擇合適的同步機制,如 synchronized、顯式鎖、訊號量等。
  2. 減少鎖的粒度:儘量減少鎖的粒度,以提高併發效能。
  3. 避免死鎖:注意避免死鎖,尤其是在使用多個鎖的情況下。
  4. 使用併發集合類:Java 提供了一些併發集合類,如 ConcurrentHashMapCopyOnWriteArrayList 等,可以簡化執行緒同步。

透過以上內容,我們詳細介紹了 Java 中的執行緒同步機制,包括基本概念、常用方法及其具體程式碼示例,並探討了使用不同同步機制的最佳實踐。掌握這些知識,能夠幫助我們編寫出更加高效和可靠的多執行緒程式。

著作權歸聚娃科技微賺淘客系統開發者團隊,轉載請註明出處!

相關文章