Java之线程与并发编程!

举报
喵手 发表于 2025/09/24 21:15:20 2025/09/24
【摘要】 开篇语哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,...

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

线程与并发编程是现代程序设计中至关重要的概念,尤其是在多核处理器的环境下。通过合理的线程管理与同步机制,程序能够更高效地执行任务,充分利用硬件资源。本文将深入探讨线程的创建与生命周期、RunnableThread类、同步与锁机制、线程池以及高级并发工具如CountDownLatchCyclicBarrierSemaphoreFuture等。

1. 线程的创建与生命周期

线程的生命周期

线程的生命周期可以分为以下几个阶段:

  • 新建(New):线程被创建,但还没有开始执行。
  • 就绪(Runnable):线程已经准备好并等待操作系统分配CPU时间片。
  • 运行(Running):线程获取到CPU资源后开始执行任务。
  • 阻塞(Blocked):线程因为某些原因被阻塞,等待某些资源或条件。
  • 死亡(Terminated):线程执行完毕或者被强制终止。

线程的创建

线程的创建有两种主要方式:

  1. 通过继承Thread
  2. 通过实现Runnable接口

示例:

  • 通过继承Thread类:

    class MyThread extends Thread {
        public void run() {
            System.out.println("Thread is running");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            MyThread thread = new MyThread();
            thread.start(); // 启动线程
        }
    }
    
  • 通过实现Runnable接口:

    class MyRunnable implements Runnable {
        public void run() {
            System.out.println("Runnable is running");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            MyRunnable myRunnable = new MyRunnable();
            Thread thread = new Thread(myRunnable);
            thread.start(); // 启动线程
        }
    }
    

2. RunnableThread

Thread

Thread类是Java中最常见的线程类,它提供了创建和控制线程的基本方法。Thread类可以通过继承和重写其run()方法来实现线程的逻辑。

Runnable接口

Runnable接口是另一种创建线程的方式,它定义了一个run()方法。通过实现Runnable接口,线程可以使用多个线程共享同一个Runnable实例。

区别

  • 使用Thread类时,每个线程只能继承一个类,因此无法继承其他类。
  • 使用Runnable接口时,类可以继承其他类,同时实现多个接口,具有更高的灵活性。

示例:

// 通过Thread创建线程
class MyThread extends Thread {
    public void run() {
        System.out.println("Thread is running");
    }
}

// 通过Runnable接口创建线程
class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Runnable is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        thread1.start(); // 启动线程

        MyRunnable myRunnable = new MyRunnable();
        Thread thread2 = new Thread(myRunnable);
        thread2.start(); // 启动线程
    }
}

3. 同步与锁机制

同步(Synchronization)

在多线程环境下,多个线程可能会同时访问共享资源,导致数据不一致或程序出错。为了避免这种问题,Java提供了同步机制。

  • synchronized关键字:通过在方法或代码块上加上synchronized关键字,确保同一时间只有一个线程能够访问该资源。

示例:

class Counter {
    private int count = 0;

    // 使用synchronized保证线程安全
    synchronized void increment() {
        count++;
    }

    synchronized void decrement() {
        count--;
    }

    public int getCount() {
        return count;
    }
}

锁机制

Java中的锁机制提供了更高级的同步方式,例如:

  • ReentrantLock:相比synchronizedReentrantLock提供了更细粒度的控制,支持可重入锁、定时锁等功能。
  • 读写锁(ReadWriteLock):适用于读多写少的场景,允许多个线程同时读共享资源,但写操作是排他的。

示例:

import java.util.concurrent.locks.ReentrantLock;

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

    void increment() {
        lock.lock();  // 获取锁
        try {
            count++;
        } finally {
            lock.unlock();  // 释放锁
        }
    }

    void decrement() {
        lock.lock();
        try {
            count--;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

4. 线程池(Executor、ExecutorService)

线程池的概念

线程池是一个可以重用的线程集合,能够有效管理线程的生命周期。它通过预先创建和管理线程来减少线程的创建和销毁开销。

Java提供了Executor框架来管理线程池,主要包含以下几种类型:

  • Executor:最基础的线程池接口,提供了执行任务的能力。
  • ExecutorService:扩展了Executor,提供了关闭线程池、提交任务、获取任务执行结果等功能。
  • ScheduledExecutorService:用于定时和周期性任务的执行。

示例:

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

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2); // 创建一个固定大小的线程池

        executor.submit(() -> {
            System.out.println("Task 1 is running");
        });

        executor.submit(() -> {
            System.out.println("Task 2 is running");
        });

        executor.shutdown(); // 关闭线程池
    }
}

5. 高级并发:CountDownLatch、CyclicBarrier、Semaphore、Future等

CountDownLatch

CountDownLatch是一个同步工具类,它允许一个或多个线程等待直到其他线程完成某些操作后再继续。CountDownLatch通过计数器来控制线程的等待,计数器初始值为一个正整数,每次调用countDown()方法将计数器减一,当计数器为零时,等待的线程继续执行。

示例:

import java.util.concurrent.CountDownLatch;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        // 启动三个线程
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println("Task is completed");
                latch.countDown(); // 每个任务完成时调用countDown
            }).start();
        }

        latch.await(); // 等待所有任务完成
        System.out.println("All tasks are completed");
    }
}

CyclicBarrier

CyclicBarrier用于让一组线程在某个点上等待,直到所有线程都到达了这个点。与CountDownLatch不同,CyclicBarrier是可重用的,即在屏障释放后可以重复使用。

示例:

import java.util.concurrent.CyclicBarrier;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            System.out.println("All threads have reached the barrier, continue execution.");
        });

        // 启动三个线程
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println("Thread is waiting at the barrier");
                try {
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Semaphore

Semaphore是一个计数信号量,允许控制同时访问某个资源的线程数量。Semaphore常用于限制并发访问某些资源的线程数。

示例:

import java.util.concurrent.Semaphore;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Semaphore semaphore = new Semaphore(2); // 限制同时只有两个线程访问

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire(); // 获取信号量
                    System.out.println(Thread.currentThread().getName() + " is working");
                    Thread.sleep(1000); // 模拟工作
                    semaphore.release(); // 释放信号量
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Future

Future是一个接口,它表示异步计算的结果。通过Future,可以在计算完成后获取返回结果、取消任务或者检测任务是否完成。

示例:

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(() -> {
            return 42; // 任务返回结果
        });

        Integer result = future.get(); // 获取任务结果
        System.out.println("Result: " + result);
        executor.shutdown();
    }
}

总结

线程与并发编程是提高程序执行效率的关键技术。通过理解和应用线程的创建与生命周期、同步与锁机制、线程池的使用,以及掌握高级并发工具如CountDownLatchCyclicBarrierSemaphoreFuture,可以有效地提升程序的性能、可扩展性与可维护性。在多线程编程中,合理的同步和资源管理至关重要,它们决定了程序的正确性和效率。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。