Java并发编程实战:深入理解锁机制、并发工具与场景应用

前言

在当今多核处理器普及的时代,充分发挥多线程的优势成为了提升程序性能的关键。Java作为一门面向对象的编程语言,提供了丰富的并发编程工具和库,使得开发者能够轻松地构建高效、稳定的并发应用。然而,对于刚接触并发编程的开发者来说,面对众多的锁机制、并发工具和复杂的场景应用,可能会感到无从下手。本文将从基础到进阶,详细讲解Java中的各种锁机制、并发工具以及常见场景的实现方法,帮助读者全面理解并掌握Java并发编程的核心知识点。

一、Java并发编程基础

1. 线程与多线程

Java通过Thread类和Runnable接口提供了多线程的支持。多线程程序在运行时会将任务分解为多个线程,这些线程可以并发执行,从而提升程序的执行效率。示例:创建并启动线程

// 实现Runnable接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程执行中...");
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        // 创建线程
        Thread thread = new Thread(new MyRunnable());
        // 启动线程
        thread.start();
    }
}

2. 同步与互斥

在多线程环境下,多个线程可能同时访问共享资源,从而引发数据不一致或竞争条件。为了避免这些问题,Java提供了多种同步机制。

二、Java中的锁机制

1. 基础锁:synchronized关键字

synchronized关键字是Java中最基本的同步机制,可以修饰方法或代码块,确保同一时间只有一个线程可以执行被锁定的代码。示例:synchronized方法

class Counter {
    private int count = 0;

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

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

示例:synchronized代码块
class Counter {
    private int count = 0;
    private Object lock = new Object();

    public void increment() {
        synchronized (lock) { // 使用锁对象
            count++;
        }
    }
}

2. ReentrantLock:可重入锁

ReentrantLock是Java并发包java.util.concurrent.locks中的一个类,提供了比synchronized更灵活的锁机制。示例:ReentrantLock的基本用法

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

class Counter {
    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock(); // 加锁
        try {
            count++;
        } finally {
            lock.unlock(); // 解锁
        }
    }
}

3. ReadWriteLock:读写锁

ReadWriteLock允许对资源进行读写分离,允许多个线程同时读取资源,但写入时需要独占锁。示例:ReadWriteLock的使用

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

class Counter {
    private int count = 0;
    private ReadWriteLock lock = new ReentrantReadWriteLock();

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

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

三、Java中的并发工具

1. CountDownLatch:计数器闭锁

CountDownLatch用于等待一组线程完成任务后再继续执行后续操作。示例:CountDownLatch的使用

import java.util.concurrent.CountDownLatch;

class Task implements Runnable {
    private CountDownLatch latch;

    public Task(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        System.out.println("任务执行中...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务完成...");
        latch.countDown(); // 通知闭锁
    }
}

public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(3); // 3个任务
        for (int i = 0; i < 3; i++) {
            new Thread(new Task(latch)).start();
        }
        try {
            latch.await(); // 等待所有任务完成
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("所有任务完成,继续执行...");
    }
}

2. Semaphore:信号量

Semaphore用于控制同时访问某一资源的线程数量。示例:Semaphore的使用

import java.util.concurrent.Semaphore;

class Task implements Runnable {
    private Semaphore semaphore;

    public Task(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire(); // 获取许可
            System.out.println(Thread.currentThread().getName() + " 正在执行...");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " 执行完成...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 释放许可
        }
    }
}

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // 最多允许2个线程同时执行
        for (int i = 0; i < 5; i++) {
            new Thread(new Task(semaphore), "线程" + i).start();
        }
    }
}

3. Executor框架:线程池

Java的Executor框架提供了一套接口和实现类,用于管理和复用线程,简化了线程池的使用。示例:线程池的使用

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

public class ExecutorDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3); // 固定大小的线程池
        for (int i = 0; i < 5; i++) {
            executor.execute(new Task());
        }
        executor.shutdown();
        try {
            executor.awaitTermination(1, TimeUnit.MINUTES); // 等待所有任务完成
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 正在执行...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 执行完成...");
    }
}

四、Java并发编程中的高级主题

1. CAS(Compare-And-Swap):无锁编程

CAS是一种无锁算法,通过比较内存中的值与预期值,如果相同则更新,否则重试。Java中的Atomic类族(如AtomicInteger)利用了CAS机制。示例:AtomicInteger的使用

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInt = new AtomicInteger(0);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                atomicInt.getAndIncrement(); // 使用CAS进行原子操作
            }).start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("最终值:" + atomicInt.get());
    }
}

2. DCL(Double-Checked Locking):双重校验锁

DCL是一种优化单例模式的实现方式,在一定程度上避免了synchronized关键字的性能开销。示例:DCL的实现

class Singleton {
    private volatile static Singleton instance;
    private Singleton() {
        // 防止反射攻击
        if (instance != null) {
            throw new RuntimeException("单例构造器被调用!");
        }
    }

    public static Singleton getInstance() {
        if (instance == null) { // 第一次检查
            synchronized (Singleton.class) {
                if (instance == null) { // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

public class DCLEntry {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();
    }
}

五、常见场景实现

1. 银行转账场景

示例:使用ReentrantLock实现银行转账

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

class Account {
    private double balance;
    private Lock lock = new ReentrantLock();

    public Account(double balance) {
        this.balance = balance;
    }

    public void transfer(Account target, double amount) {
        lock.lock();
        try {
            if (balance >= amount) {
                balance -= amount;
                target.balance += amount;
            }
        } finally {
            lock.unlock();
        }
    }

    public double getBalance() {
        return balance;
    }
}

public class BankTransfer {
    public static void main(String[] args) {
        Account alice = new Account(1000);
        Account bob = new Account(0);
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                alice.transfer(bob, 1);
            }
        }).start();
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                bob.transfer(alice, 1);
            }
        }).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Alice的余额:" + alice.getBalance());
        System.out.println("Bob的余额:" + bob.getBalance());
    }
}

2. 售票系统场景

示例:使用Semaphore实现售票系统

import java.util.concurrent.Semaphore;

class TicketSeller implements Runnable {
    private static int tickets = 100;
    private Semaphore semaphore;

    public TicketSeller(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        while (true) {
            try {
                semaphore.acquire(); // 获取许可
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName() + " 卖出一张票,剩余票数:" + (tickets--));
                } else {
                    System.out.println("票已售罄!");
                    break;
                }
                semaphore.release(); // 释放许可
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class TicketSystem {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(5); // 允许5个线程同时售票
        for (int i = 0; i < 10; i++) {
            new Thread(new TicketSeller(semaphore), "售票员" + i).start();
        }
    }
}

六、总结

Java并发编程是提升程序性能和扩展性的关键,但同时也需要开发者具备扎实的理论基础和丰富的实践经验。本文详细介绍了Java中的锁机制、并发工具以及常见场景的实现方法,并通过代码示例帮助读者更好地理解和掌握相关知识点。希望本文能够为读者提供有价值的参考,助力他们在Java并发编程领域更进一步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值