当前位置: 首页 > article >正文

Java 多线程编程介绍


Java学习资料

Java学习资料

Java学习资料


一、引言

在现代软件开发中,处理复杂的任务和提高程序的性能是至关重要的。单线程程序一次只能执行一个任务,在处理耗时操作时会导致程序响应缓慢。Java 多线程编程为解决这类问题提供了有效的方案。通过多线程,程序可以同时执行多个任务,充分利用多核处理器的计算能力,提高程序的并发性和响应速度。

二、线程的基本概念

2.1 线程与进程

进程:是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位。每个进程都有自己独立的内存空间和系统资源。例如,当我们打开一个浏览器,就启动了一个浏览器进程。

线程:是进程中的一个执行单元,是 CPU 调度和分派的基本单位。一个进程可以包含多个线程,这些线程共享进程的内存空间和系统资源。比如在浏览器进程中,可以有一个线程负责渲染页面,另一个线程负责下载文件。

2.2 线程的状态

Java 中的线程有六种状态,定义在 Thread.State 枚举中:

新建(NEW):当创建一个 Thread 对象时,线程处于新建状态,此时线程还没有开始执行。

就绪(RUNNABLE):调用线程的 start() 方法后,线程进入就绪状态,等待 CPU 调度执行。

运行(Running):当 CPU 分配时间片给该线程时,线程进入运行状态,开始执行 run() 方法中的代码。

阻塞(BLOCKED):线程在获取同步锁失败、等待 I/O 操作完成等情况下会进入阻塞状态,暂时停止执行。

等待(WAITING):线程调用 Object.wait()、Thread.join() 等方法后会进入等待状态,需要其他线程唤醒。

超时等待(TIMED_WAITING):与等待状态类似,但可以指定等待的时间,超时后线程会自动唤醒,例如调用 Thread.sleep(long millis) 方法。

终止(TERMINATED):线程的 run() 方法执行完毕或者因为异常退出,线程进入终止状态。

三、创建线程的方式

3.1 继承 Thread 类

通过继承 Thread 类,并重写 run() 方法来定义线程的执行逻辑。示例代码如下:

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadInheritanceExample {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        thread1.start();
        thread2.start();
    }
}

3.2 实现 Runnable 接口

实现 Runnable 接口的 run() 方法,然后将实现类的实例作为参数传递给 Thread 类的构造函数。示例代码如下:

  @Override
  class MyRunnable implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class RunnableExample {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable);
        Thread thread2 = new Thread(myRunnable);
        thread1.start();
        thread2.start();
    }
}

3.3 实现 Callable 接口

Callable 接口与 Runnable 接口类似,但 Callable 的 call() 方法可以有返回值,并且可以抛出异常。通常与 Future 接口配合使用来获取线程执行的结果。示例代码如下:

import java.util.concurrent.*;

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            sum += i;
        }
        return sum;
    }
}

public class CallableExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        MyCallable myCallable = new MyCallable();
        Future<Integer> future = executor.submit(myCallable);
        Integer result = future.get();
        System.out.println("Result: " + result);
        executor.shutdown();
    }
}

四、线程同步与并发控制

4.1 同步方法和同步块

当多个线程访问共享资源时,可能会出现数据不一致的问题,这就需要进行线程同步。Java 提供了 synchronized 关键字来实现线程同步。

同步方法:在方法声明中使用 synchronized 关键字,示例代码如下:

class Counter {
    private int count = 0;

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

    public int getCount() {
        return count;
    }
}

同步块:使用 synchronized 关键字修饰代码块,指定同步的对象,示例代码如下:

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

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

    public int getCount() {
        return count;
    }
}

4.2 ReentrantLock

ReentrantLock 是 Java 提供的一个可重入锁,与 synchronized 关键字类似,但功能更强大。示例代码如下:

import java.util.concurrent.locks.ReentrantLock;

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

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

4.3 wait()、notify() 和 notifyAll()

这三个方法是 Object 类的方法,用于线程间的协作。wait() 方法使当前线程进入等待状态,notify() 方法唤醒在此对象监视器上等待的单个线程,notifyAll() 方法唤醒在此对象监视器上等待的所有线程。示例代码如下:

class SharedResource {
    private boolean flag = false;

    public synchronized void waitForFlag() throws InterruptedException {
        while (!flag) {
            wait();
        }
        System.out.println("Flag is set, continuing...");
    }

    public synchronized void setFlag() {
        flag = true;
        notify();
    }
}

五、线程池

线程池是一种管理线程的机制,它可以预先创建一定数量的线程,当有任务提交时,从线程池中获取线程来执行任务,任务执行完毕后线程不会销毁,而是返回到线程池中等待下一个任务。使用线程池可以减少线程创建和销毁的开销,提高程序的性能。Java 提供了 ExecutorService 接口和 Executors 工厂类来创建和管理线程池。示例代码如下:

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

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is executing task.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 5; i++) {
            executor.submit(new Task());
        }
        executor.shutdown();
    }
}

六、总结

Java 多线程编程是提高程序性能和响应速度的重要手段。通过创建线程、进行线程同步和并发控制以及使用线程池等技术,我们可以充分发挥多核处理器的优势,开发出高效、稳定的多线程应用程序。但同时,多线程编程也带来了一些问题,如线程安全、死锁等,需要开发者在编程过程中谨慎处理。


http://www.kler.cn/a/520124.html

相关文章:

  • 代码工艺:实践 Spring Boot TDD 测试驱动开发
  • LabVIEW 保存文件 生产者/消费者设计
  • 2024年度总结:技术探索与个人成长的交织
  • React和Vue有什么区别,如何选择?
  • C++异常处理
  • 【Matlab高端绘图SCI绘图模板】第05期 绘制高阶折线图
  • linux-ubuntu学习笔记碎记
  • Git 分支管理与多人协作实战指南
  • 【学习笔记】深度学习网络-深度前馈网络(MLP)
  • ios swift画中画技术尝试
  • 使用Docker构建Node.js应用的详细指南
  • chrome源码剖析—进程通信
  • 99.16 金融难点通俗解释:营业总收入
  • 关于CAN(FD)转以太网详细介绍
  • Hive的安装与部署
  • 算法随笔_23: 通过删除字母匹配到字典里最长单词
  • Windows Defender添加排除项无权限的解决方法
  • 计算机视觉中的目标检测技术
  • 数论算法笔记
  • 【C++高并发服务器WebServer】-7:共享内存
  • 【Kubernetes】Pod生命周期、初始化容器、主容器
  • 第18章 走进xUnit:测试驱动开发的关键工具
  • Docker 从零开始掌握容器化技术
  • 数据融合的经典模型:早期融合、中期融合与后期融合的对比
  • appium自动化环境搭建
  • 12.Shader开发概述