当前位置:首页 » 《随便一记》 » 正文

深入探讨Java多线程

23 人参与  2024年09月11日 16:01  分类 : 《随便一记》  评论

点击全文阅读


我的主页:2的n次方_    

在这里插入图片描述

 

1. 多线程的概念

多线程是指在同一个程序中同时执行多个线程的技术。线程是操作系统能够独立调度和执行的最小单位。在Java中,线程由Thread类来表示,所有的线程都是通过这个类或其子类来创建和控制的。通过合理的多线程设计,程序可以在一个处理器上同时执行多个任务,极大地提高了程序的执行效率。

2. Java中实现多线程的方式

2.1 继承Thread类

通过继承Thread类并重写其run()方法,我们可以创建一个新的线程。run()方法包含了线程在启动后要执行的代码。

class MyThread extends Thread {    @Override    public void run() {        for (int i = 0; i < 5; i++) {            System.out.println(Thread.currentThread().getName() + " - " + i);        }    }}public class Main {    public static void main(String[] args) {        MyThread thread1 = new MyThread();        MyThread thread2 = new MyThread();                thread1.start();        thread2.start();    }}

在这个例子中,我们创建了两个线程,每个线程都会执行run()方法中的代码。start()方法用于启动线程,而不是直接调用run()方法。

2.2 实现Runnable接口

相比继承Thread类,实现Runnable接口更为灵活,因为Java支持单继承但允许实现多个接口。

class MyRunnable implements Runnable {    @Override    public void run() {        for (int i = 0; i < 5; i++) {            System.out.println(Thread.currentThread().getName() + " - " + i);        }    }}public class Main {    public static void main(String[] args) {        Thread thread1 = new Thread(new MyRunnable());        Thread thread2 = new Thread(new MyRunnable());                thread1.start();        thread2.start();    }}

在这个例子中,我们创建了两个线程,并分别传入实现了Runnable接口的对象。Thread类的构造函数接受一个Runnable对象,这使得线程的创建更加灵活。

2.3 使用Callable和Future

Runnable接口的run()方法无法返回结果,而Callable接口的call()方法则可以返回结果,并且可以抛出异常。配合Future接口,Callable可以用来处理需要返回值的任务。

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> {    @Override    public Integer call() throws Exception {        int sum = 0;        for (int i = 0; i < 5; i++) {            sum += i;        }        return sum;    }}public class Main {    public static void main(String[] args) {        ExecutorService executor = Executors.newFixedThreadPool(2);        Future<Integer> future = executor.submit(new MyCallable());                try {            Integer result = future.get();            System.out.println("Sum: " + result);        } catch (InterruptedException | ExecutionException e) {            e.printStackTrace();        }                executor.shutdown();    }}

在这个例子中,我们通过Callable实现了一个简单的求和任务,并使用ExecutorService来管理线程执行。通过Future对象,我们可以获取线程执行的结果。 

2.4 线程池的使用

线程池是一种管理多个线程的工具,可以有效地减少线程的创建和销毁开销,提高资源利用率。Java通过ExecutorService提供了多种创建线程池的方式。

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;class MyRunnable implements Runnable {    @Override    public void run() {        for (int i = 0; i < 5; i++) {            System.out.println(Thread.currentThread().getName() + " - " + i);        }    }}public class Main {    public static void main(String[] args) {        ExecutorService executor = Executors.newFixedThreadPool(2);                for (int i = 0; i < 5; i++) {            executor.submit(new MyRunnable());        }                executor.shutdown();    }}

在这个例子中,我们创建了一个固定大小的线程池,并向线程池提交了多个任务。线程池会合理分配线程来执行这些任务。

3. 线程的生命周期 

Java线程的生命周期包括多个状态,从线程的创建到终止,线程会经历不同的状态转换。理解线程的生命周期对于编写高效的多线程应用程序至关重要。

3.1 新建状态(New)

当一个线程对象被创建时,它处于新建状态。此时,线程对象已经存在,但还没有调用start()方法来启动线程。新建状态是线程生命周期的起始点,在这个状态下,线程还没有分配任何CPU资源。

Thread thread = new Thread(() -> {    // Thread code here});

3.2 就绪状态(Runnable)

当调用start()方法后,线程从新建状态进入就绪状态。在这个状态下,线程已经具备了运行的条件,等待操作系统调度器分配CPU时间片来执行。需要注意的是,在Java中,“就绪状态”并不意味着线程正在运行,而是等待被调度。

thread.start();  // Thread moves to the Runnable state

 线程调用start()后,立即进入就绪状态。操作系统的线程调度器会根据线程的优先级等条件,将就绪状态的线程分配到CPU上执行。

3.3 运行状态(Running)

当线程获得CPU时间片,开始执行run()方法中的代码时,线程进入运行状态。这是线程生命周期中唯一实际执行代码的状态。线程在这个状态下进行任务处理,直到被操作系统中断或自主放弃CPU资源。

@Overridepublic void run() {    for (int i = 0; i < 5; i++) {        System.out.println(Thread.currentThread().getName() + " - " + i);    }}

在这个例子中,线程进入运行状态并执行run()方法中的代码。运行状态通常非常短暂,因为操作系统会定期中断线程,以允许其他就绪线程获得执行机会。

3.4 阻塞状态(Blocked)

线程在执行过程中可能会因为某些原因(如等待资源、I/O操作、线程同步)而暂停运行,进入阻塞状态。在这个状态下,线程暂时放弃了CPU资源,直到满足特定条件(如获取锁或完成I/O操作),线程才能重新进入就绪状态。

阻塞状态可以进一步细分为以下几种:

等待阻塞(Waiting Blocked):线程通过调用wait()方法进入等待队列,等待其他线程通过notify()notifyAll()方法唤醒它。

超时等待阻塞(Timed Waiting Blocked):线程通过调用sleep(long millis)join(long millis)wait(long millis)等方法进入此状态,线程会在指定时间后自动苏醒,或在满足条件时被唤醒。

同步阻塞(Synchronized Blocked):线程试图获取对象的同步锁,但该锁已被其他线程持有,此时线程进入同步阻塞状态。

synchronized (lock) {    // Thread blocks if lock is held by another thread}

 在这个例子中,线程试图获取锁对象lock,如果该锁被其他线程持有,当前线程将进入同步阻塞状态,直到锁可用。

3.5 终止状态(Terminated)

当线程的run()方法执行完毕或抛出未捕获的异常时,线程进入终止状态。此时,线程的生命周期结束,不能再重新启动。线程进入终止状态后,系统会释放线程所占用的所有资源。

thread.join();  // Waits for thread to die

调用join()方法后,主线程会等待thread线程终止后才继续执行。此时,thread线程已进入终止状态。


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/158329.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1