Java核心知识体系10-线程管理

Java系列

Java核心知识体系1:泛型机制详解
Java核心知识体系2:注解机制详解
Java核心知识体系3:异常机制详解
Java核心知识体系4:AOP原理和切面应用
Java核心知识体系5:反射机制详解
Java核心知识体系6:集合框架详解
Java核心知识体系7:线程不安全分析
Java核心知识体系8:Java如何保证线程安全性
Java核心知识体系9-并发与多线程:线程基础

在Java程序开发中,线程管理是一个至关重要的方面。它涉及到如何有效地创建、调度、同步和销毁线程,以确保程序的性能、响应性和稳定性。以下是对Java线程管理的详细探讨。

1 线程的基本概念

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。每个线程都有一个独立的执行路径,但共享进程的资源,如内存和文件句柄。在Java中,线程可以通过继承Thread类或实现Runnable接口来创建。

此外,Java 5开始,引入了java.util.concurrent包,提供了更多的并发工具,如Callable接口与Future接口,它们主要用于任务执行。

2 线程的创建与启动

2.1 继承Thread类

  • 创建一个类继承自Thread类。

  • 重写run()方法,该方法包含了线程要执行的任务。

  • 创建该类的对象,并调用start()方法启动线程。

    class MyThread extends Thread {
    public void run() {
    System.out.println("线程运行中");
    }
    }

    public class ThreadDemo {
    public static void main(String[] args) {
    MyThread t = new MyThread();
    t.start(); // 调用start()方法来启动线程
    }
    }

2.2 实现Runnable接口

  • 创建一个类实现Runnable接口。

  • 实现run()方法,该方法同样包含了线程要执行的任务。

  • 将该类的对象作为参数传递给Thread类的构造函数,创建Thread对象。

  • 调用Thread对象的start()方法启动线程。

    class MyRunnable implements Runnable {
    public void run() {
    System.out.println("线程运行中");
    }
    }

    public class RunnableDemo {
    public static void main(String[] args) {
    Thread t = new Thread(new MyRunnable());
    t.start(); // 调用start()方法来启动线程
    }
    }

3 线程的同步与通信

由于多个线程可能会同时访问共享资源,因此需要使用同步机制来确保数据的正确性和一致性。Java提供了多种同步机制,如synchronized关键字、wait()notify()方法、以及ReentrantLock等。

3.1 synchronized关键字

  1. 可以用于方法或代码块上,以确保同一时刻只有一个线程能够执行该方法或代码块。

  2. 当一个线程持有某个对象的锁时,其他线程将无法访问该对象的同步方法或代码块,直到锁被释放。

    public class SynchronizedExample {
    private int count = 0;

     // 同步方法
     public synchronized void increment() {
         count++;
     }
    
     public synchronized int getCount() {
         return count;
     }
    
     public static void main(String[] args) throws InterruptedException {
         SynchronizedExample example = new SynchronizedExample();
    
         // 创建多个线程来测试同步
         Thread t1 = new Thread(() -> {
             for (int i = 0; i < 1000; i++) {
                 example.increment();
             }
         });
    
         Thread t2 = new Thread(() -> {
             for (int i = 0; i < 1000; i++) {
                 example.increment();
             }
         });
    
         t1.start();
         t2.start();
    
         // 等待线程执行完毕
         t1.join();
         t2.join();
    
         // 输出最终结果
         System.out.println("Final count: " + example.getCount()); // 最终输出2000
     }
    

    }

3.2 wait()和notify()方法

这两个方法用于在线程之间进行通信。

  1. wait()方法使当前线程等待,直到其他线程调用notify()notifyAll()方法唤醒它。
  2. notify()方法唤醒一个等待该对象的线程(如果有多个线程在等待,则选择其中一个),而notifyAll()方法唤醒所有等待该对象的线程。
# 先写后读
public class WaitNotifyExample {
    private final Object lock = new Object();
    private boolean ready = false;

    public void writer() throws InterruptedException {
        synchronized (lock) {
            // 模拟写操作
            Thread.sleep(1000); // 假设写操作需要1秒
            System.out.println("Data is ready");
            ready = true;
            lock.notify(); // 唤醒等待的线程
        }
    }

    public void reader() throws InterruptedException {
        synchronized (lock) {
            while (!ready) {
                lock.wait(); // 等待数据准备好
            }
            // 读取数据
            System.out.println("Data has been read");
        }
    }

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

        Thread writerThread = new Thread(example::writer);
        Thread readerThread = new Thread(example::reader);

        writerThread.start();
        readerThread.start();
    }
}

3.3 ReentrantLock

  1. 提供了比synchronized更灵活的锁机制。
  2. 可以显式地加锁和解锁,还支持公平锁和非公平锁等特性。

四、线程的生命周期与状态

Java线程在其生命周期中会经历多种状态,包括新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)和终止(Terminated)。

  • 新建(New):线程被创建但尚未启动。
  • 就绪(Runnable):线程已启动且正在等待CPU分配时间片。
  • 运行(Running):线程正在执行其任务。
  • 阻塞(Blocked):线程因等待某个条件而暂时停止执行。
  • 等待(Waiting) :线程因调用wait()方法而等待其他线程唤醒。
  • 超时等待(Timed Waiting):线程在等待某个条件的同时还设置了一个超时时间。
  • 终止(Terminated):线程已完成任务并退出。

5 线程池

为了更有效地管理线程,Java提供了线程池机制。线程池是一种用于管理和复用线程的框架,它允许开发者以较小的开销来创建和管理大量的线程。Java中的ExecutorService接口及其实现类(如ThreadPoolExecutor)提供了强大的线程池功能。

Java中提供了几种常见的线程池类型,包括:

  1. FixedThreadPool(固定大小线程池):包含固定数量的线程,适用于需要限制并发线程数量的场景。
  2. CachedThreadPool(缓存线程池):不固定线程数量,可以根据需要自动创建新线程,适用于短期异步任务。
  3. SingleThreadPool(单线程池):只包含一个工作线程,保证所有任务按顺序执行,适用于需要保持任务顺序执行的场景。
  4. ScheduledThreadPool(定时线程池):可以执行定时任务和周期性任务。
  5. WorkStealingPool(工作窃取线程池):Java 8中引入的一种新类型的线程池,主要用于处理耗时任务,适用于需要大量并行任务、任务之间没有依赖关系的情况。

在后续的章节里面,我们会专门来详细介绍下线程池的使用

6 最佳实践

  • 避免创建过多的线程:过多的线程会导致上下文切换频繁,从而降低系统性能。
  • 合理设置线程优先级:根据任务的紧急程度和重要性来设置线程的优先级。
  • 使用线程安全的集合:在多线程环境下使用线程安全的集合来避免数据不一致的问题。
  • 避免死锁:在设计多线程程序时要特别注意避免死锁的发生。

综上所述,Java线程管理是一个复杂而重要的领域。通过合理地创建、调度、同步和销毁线程,可以显著提高程序的性能、响应性和稳定性。同时,开发者还需要遵循一些最佳实践来避免常见的问题和陷阱。

相关推荐
Oneforlove_twoforjob5 分钟前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
向宇it22 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行24 分钟前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
星河梦瑾1 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富1 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想1 小时前
JMeter 使用详解
java·jmeter
言、雲1 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇1 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
Yvemil72 小时前
《开启微服务之旅:Spring Boot 从入门到实践》(三)
java
Anna。。2 小时前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea