深入理解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实例才能继续使用。*/
    
相关文章
|
7天前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
41 0
|
19天前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
51 16
|
28天前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
1月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
2月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
293 83
|
2月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
135 0
|
2月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
240 83
|
3月前
|
移动开发 Java
说一说 Java 是如何实现线程间通信
我是小假 期待与你的下一次相遇 ~