深入理解Java中的多线程与并发机制

简介: 本文将详细探讨Java中多线程的概念、实现方式及并发机制,包括线程的生命周期、同步与锁机制以及高级并发工具。通过实例代码演示,帮助读者理解如何在Java中有效地处理多线程和并发问题,提高程序的性能和响应能力。

一、引言
多线程和并发编程是现代软件开发中的重要课题,它们在提升程序性能、改善用户体验方面发挥着关键作用。Java作为一种广泛使用的编程语言,提供了丰富的多线程和并发工具,帮助开发者应对复杂的并发需求。本文将从基本概念入手,逐步深入探讨Java中的多线程与并发机制。

二、线程的基本概念

  1. 线程的定义与特性
    • 线程是操作系统能够进行运算调度的最小单位。
    • 每个线程都有自己的程序计数器、栈、局部变量等资源。
  2. 线程的状态与生命周期
    • 新建(New):线程对象创建后,但尚未启动。
    • 就绪(Runnable):线程对象创建后,等待CPU时间片。
    • 运行(Running):线程获得CPU时间片,正在执行。
    • 阻塞(Blocked):线程因等待某些资源而暂时停止运行。
    • 死亡(Terminated):线程执行完毕或因异常退出。

三、实现多线程的方式

  1. 继承Thread类

    class MyThread extends Thread {
         
        public void run() {
         
            System.out.println("MyThread is running");
        }
    }
    
    public class Test {
         
        public static void main(String[] args) {
         
            MyThread myThread = new MyThread();
            myThread.start();
        }
    }
    
  2. 实现Runnable接口

    class MyRunnable implements Runnable {
         
        public void run() {
         
            System.out.println("MyRunnable is running");
        }
    }
    
    public class Test {
         
        public static void main(String[] args) {
         
            Thread thread = new Thread(new MyRunnable());
            thread.start();
        }
    }
    
  3. 使用Callable和Future

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    class MyCallable implements Callable<Integer> {
         
        public Integer call() throws Exception {
         
            return 123;
        }
    }
    
    public class Test {
         
        public static void main(String[] args) {
         
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Future<Integer> future = executor.submit(new MyCallable());
            try {
         
                System.out.println("Result: " + future.get());
            } catch (InterruptedException | ExecutionException e) {
         
                e.printStackTrace();
            } finally {
         
                executor.shutdown();
            }
        }
    }
    

四、线程的同步与锁机制

  1. synchronized关键字

    • 用于修饰方法或代码块,确保同一时刻只有一个线程执行被修饰的代码段。

      class Counter {
             
        private int count = 0;
      
        public synchronized void increment() {
             
            count++;
        }
      
        public int getCount() {
             
            return count;
        }
      }
      
  2. ReentrantLock类

    • 提供比synchronized更灵活的锁机制,可设置公平性、获取锁的超时时间等。
      ```java
      import java.util.concurrent.locks.ReentrantLock;

    class Counter {

    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
    
    public int getCount() {
        return count;
    }
    

    }
    ```

  3. 读写锁(ReadWriteLock)

    • 允许多个线程同时读,但在写操作时互斥。适用于读多写少的场景。
      ```java
      import java.util.concurrent.locks.ReadWriteLock;
      import java.util.concurrent.locks.ReentrantReadWriteLock;

    class Data {

    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private String data;
    
    public void setData(String data) {
        rwLock.writeLock().lock();
        try {
            this.data = data;
        } finally {
            rwLock.writeLock().unlock();
        }
    }
    
    public String getData() {
        rwLock.readLock().lock();
        try {
            return data;
        } finally {
            rwLock.readLock().unlock();
        }
    }
    

    }
    ```

  4. 条件变量(Condition)

    • 配合锁使用,用于线程间通信和协调。
      ```java
      import java.util.concurrent.locks.Condition;
      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;

    class SharedObject {

    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private boolean available = false;
    
    public void produce() {
        lock.lock();
        try {
            available = true;
            condition.signalAll();  // 唤醒所有等待的线程
        } finally {
            lock.unlock();
        }
    }
    
    public void consume() {
        lock.lock();
        try {
            while (!available) {  // 使用while循环防止假唤醒
                condition.await(); // 等待直到收到信号
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
    

    }
    ```

  5. Semaphore(信号量)

    • 控制对资源的访问许可数量,常用于限制同时访问某个资源的线程数。
      ```java
      import java.util.concurrent.Semaphore;

    class LimitedResource {

    private Semaphore semaphore = new Semaphore(5); // 同时最多允许5个线程访问
    
    public void accessResource() {
        try {
            semaphore.acquire(); // 获取许可
            // 访问资源...
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            semaphore.release(); // 释放许可
        }
    }
    

    }
    ```

  6. CountDownLatch(倒计时器)

    • 让一个或多个线程等待其他线程完成指定任务后再继续执行。
      ```java
      import java.util.concurrent.CountDownLatch;

    class Task implements Runnable {

    private final CountDownLatch latch;
    
    public Task(CountDownLatch latch) {
        this.latch = latch;
    }
    
    public void run() {
        try {
            System.out.println("Task is running");
            Thread.sleep(1000L); // 模拟任务耗时
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            latch.countDown(); // 任务完成,计数器减1
        }
    }
    

    }

    public class Test {

    public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(3); // 初始化计数器为3
        new Thread(new Task(latch)).start(); // 开始3个任务线程
        new Thread(() -> {
            try {
                latch.await(); // 主线程等待任务线程完成
                System.out.println("All tasks completed");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start(); // 启动等待线程
    }
    

    }
    ```

  7. CyclicBarrier(循环屏障)

    • 让一组线程在到达某个点前相互等待,然后同时执行。适用于多阶段任务。
      ```java
      import java.util.concurrent.BrokenBarrier;
      import java.util.concurrent.CyclicBarrier;
      import java.util.concurrent.Phaser; // Phaser也可以作为CyclicBarrier的替代方案,功能更强大。

    class Task implements Runnable {

    private final CyclicBarrier barrier;
    private final int id;
    
    public Task(CyclicBarrier barrier, int id) {
        this.barrier = barrier;
        this.id = id;
    }
    
    public void run() {
        try {
            System.out.println("Task " + id + " is running");
            Thread.sleep(1000L); // 模拟任务耗时
            barrier.await(); // 等待其他线程到达屏障点并继续执行。如果其他线程已经到达屏障点,则立即返回,不会阻塞当前线程。当最后一个线程到达屏障点后,所有等待的线程将继续执行。可以配合broken参数来中断等待。如果broken为true,则抛出BrokenBarrierException异常,并重置屏障状态。如果不传broken参数,默认为false。如果所有线程都调用了await(),则调用await()的线程将不会被阻塞,而是直接返回。这意味着,如果有一个线程因为某种原因没有调用await(),那么其他所有线程都将一直等待下去,除非有线程调用reset()方法。注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrierInstance实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrsier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclICBarrIER实例。*/ /*注意,CyclICBArrIEr实例是不能重复使用的,一旦所有线程都调CBArrIEr()函数或者被重置之CBArrIEr()函数或者被重置之后,这个CBArrIER实例就不能再次使用CBArrIEr()函数或者被重置之后,这个CBArrIEr实例就不能再次使用了。如果需要重用的话就必须重新创建一个新的CBArrIEr实例。*/ /*注意,CBArrIEr实例是不能重复使用的,一旦所有线程都调CBArrIEr()函数或者被重置之CBArrIEr()函数或者被重置之后,这个CBArrIER实例就不能再次使用了。如果需要重用的话就必须重新创建一个新的CBArrIEr实例。*/ /*注意,CylCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CBArrIEr实例才能继续使用。*/ /*注意,CycleBarrier是不能够重复使用的,一旦所有的线程都调用了await方法或者被重置之后,这个CycleBarrier就不能再用了。如果需要重用的话就必须重新创建一个新的CycleBarrier实例。*/ /*注意,CylCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CBArrIEr实例才能继续使用。*/ /*注意,CycleBarrier是不能够重复使用的,一旦所有的线程都待方法或者被重置之后,这个CycleBarrier就不能再用了。如果需要重用的话就必须重新创建一个新的CycleBarrier实例。*/ /*注意,CycleBarrier是不能够重复使用的,一次使用后就要重新创建新的CycleBarrier实例才能继续使用。*/ /*注意, CylCEBArrIEr实例是不能重复使用的,一旦所有的线程都调用了await方法或者被重置之后,这个CycleBarrier就不能再用了。如果需要重用的话就必须重新创建一个新的CycleBarrCylCEBArrIEr实例才能继续使用。*/ /*注意, CylCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBarrIER实例才能继续使用。*/ /*注意, ClCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycCEBArrIEr实例才能继续使用。*/ /*注意, CyleCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBarrIER实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBarrIER实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrCylceBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/
    
相关文章
|
6天前
|
监控 Java Linux
Java 性能调优:调整 GC 线程以获得最佳结果
Java 性能调优:调整 GC 线程以获得最佳结果
39 11
|
1天前
|
Java
|
1天前
|
Java
【编程进阶知识】揭秘Java多线程:并发与顺序编程的奥秘
本文介绍了Java多线程编程的基础,通过对比顺序执行和并发执行的方式,展示了如何使用`run`方法和`start`方法来控制线程的执行模式。文章通过具体示例详细解析了两者的异同及应用场景,帮助读者更好地理解和运用多线程技术。
6 1
|
3天前
|
并行计算 Java 调度
深入理解Java中的多线程编程
【10月更文挑战第6天】 本文将探讨Java中多线程编程的基本概念、实现方式及其在实际项目中的应用。通过详细的示例和解释,读者能够掌握如何在Java中有效地使用多线程来提高程序的性能和响应能力。
8 1
|
4天前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
【10月更文挑战第6天】在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
12 2
|
5天前
|
监控 Java 调度
Java有哪几种方式创建线程?
本文详细介绍了Java中创建线程的四种主要方法:继承`Thread`类、实现`Runnable`接口、实现`Callable`接口配合`Future`,以及使用`Executor`框架。每种方法都有其独特特性和适用场景。通过示例代码和特点分析,帮助开发者根据具体需求选择合适的方式。
14 3
|
6天前
|
Java 数据处理 数据库
Java多线程的理解和应用场景
Java多线程的理解和应用场景
20 1
|
22小时前
|
Java 应用服务中间件 测试技术
Java21虚拟线程:我的锁去哪儿了?
【10月更文挑战第8天】
8 0
|
3天前
|
Java 程序员 开发者
Java中的多线程基础与实用技巧
【10月更文挑战第7天】本文旨在通过浅显易懂的语言和生动的比喻,向读者展示Java中多线程编程的世界。我们将一起探索创建线程的不同方法,理解线程生命周期的奥秘,并通过一些实用的技巧来避免常见的多线程陷阱。无论你是初学者还是有一定经验的开发者,这篇文章都将为你揭开多线程编程的神秘面纱,让你在并发编程的道路上走得更稳、更远。
|
3天前
|
Java 调度
深入理解Java中的多线程编程
【10月更文挑战第6天】 本文将通过通俗易懂的语言,详细讲解Java多线程编程的基本概念、使用方法以及注意事项。从简单的线程创建到高级的线程同步与通信,帮助您全面掌握Java多线程编程的核心知识,提升程序运行效率和性能。
8 0