Java零基础之多线程篇:线程控制

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

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

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

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

前言

  在计算机科学中,多线程是现代操作系统和应用程序的关键概念之一。通过使用多线程,可以同时执行多个任务,提高程序的运行效率。在Java开发语言中,多线程的概念被广泛应用,并且Java提供了丰富的多线程控制机制,使得开发人员能够更好地控制线程的行为。

  本文将介绍Java多线程中的线程控制相关内容,包括线程的创建和启动、线程的睡眠和唤醒、线程的等待和通知等方面。通过掌握这些线程控制技术,我们可以更加灵活地处理多线程程序中的并发问题。

摘要

  本文将介绍Java多线程中的线程控制相关内容,包括线程的创建和启动、线程的睡眠和唤醒、线程的等待和通知等方面。通过对这些线程控制技术的讲解和实践,我们可以更好地理解和应用多线程编程。

简介

  在Java中,线程是最基本的执行单元。通过创建和启动线程,我们可以同时执行多个任务。Java提供了多种方式来创建和启动线程,包括继承Thread类、实现Runnable接口、使用线程池等。

  在多线程程序中,线程的睡眠和唤醒是非常重要的操作。线程的睡眠可以通过Thread类的sleep()方法实现,而线程的唤醒可以通过调用线程的notify()notifyAll()方法来实现。

  另外,线程的等待和通知也是多线程编程中常用的技术。线程的等待可以通过调用对象的wait()方法实现,而线程的通知可以通过调用对象的notify()notifyAll()方法来实现。

源代码解析

线程的创建和启动

  在Java中,我们可以通过继承Thread类来创建一个线程类,然后通过调用该线程类的start()方法来启动线程。下面是一个简单的示例:

package com.example.javase.ms.threadDemo.day3;

/**
 * @Author ms
 * @Date 2024-04-12 18:27
 */
public class MyRunnable implements Runnable {
    public void run() {
        // 线程执行的代码
        System.out.println("线程执行啦!");
    }
}
package com.example.javase.ms.threadDemo.day3;

/**
 * @Author ms
 * @Date 2024-04-12 18:27
 */
public class ThreadDemo {

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();

        System.out.println("主线程执行啦!");
    }
}

  上述代码中,我们定义了一个继承自Thread类的MyThread类,并在该类中重写了run方法。在ThreadDemo 类中创建MyThread对象,并调用start()方法来启动线程。

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

线程的睡眠和唤醒

案例1:

线程的睡眠可以通过Thread类的sleep()方法实现。下面是一个示例:

package com.example.javase.ms.threadDemo.day3;

import java.time.LocalTime;

/**
 * @Author ms
 * @Date 2024-04-12 19:37
 */
public class ThreadSleepTest {
    public static void main(String[] args) {
        try {
            System.out.println("睡眠前:" + LocalTime.now());
            Thread.sleep(3000); // 线程睡眠1秒
            System.out.println("睡眠后:" + LocalTime.now());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  上述代码中,演示了如何在Java中使用Thread.sleep()方法使当前线程暂停执行一段时间。在这个例子中,线程将暂停执行3000毫秒,也就是3秒。

代码分析
  1. 程序首先打印出睡眠前的时间,使用LocalTime.now()获取当前的本地时间(不包含日期信息)。

  2. 接着,Thread.sleep(3000)调用使当前线程进入睡眠状态,暂停执行3秒钟。在这段时间内,当前线程不会执行任何操作,并且不会占用CPU资源。

  3. 如果在sleep期间线程被中断,InterruptedException将被抛出。在catch块中处理这个异常,打印堆栈跟踪信息。

  4. 睡眠结束后,程序再次打印出睡眠后的时间。

运行结果

  当你运行这个程序时,你会看到控制台输出两次时间,第一次是程序开始睡眠前的时间,第二次是睡眠结束后的时间。两次输出的时间间隔大约是3秒,这由Thread.sleep(3000)指定。

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

注意事项
  • Thread.sleep()方法接受的参数是毫秒数,即睡眠的时间长度。
  • InterruptedException是一个检查型异常,必须显式处理(try-catch)或声明抛出(throws)。
  • 在多线程程序中,sleep()方法是一种简单的线程调度机制,但不是最精确或最可靠的方法。例如,线程可能会比预期的睡眠时间稍微长一些才被唤醒,这取决于操作系统的线程调度策略。
  • 为了避免在睡眠期间占用CPU资源,可以在调用sleep()之前将线程的状态设置为Thread.State.WAITING

这个简单的例子展示了Thread.sleep()方法的基本用法,它是Java多线程编程中常用的工具之一。在实际应用中,sleep()方法可以用来实现线程的延迟执行、时间间隔控制等。

案例2:

  线程的唤醒可以通过调用线程的notify()notifyAll()方法来实现。下面是一个示例:

package com.example.javase.ms.threadDemo.day3;

/**
 * @Author ms
 * @Date 2024-04-12 19:42
 */
public class MyThread_wait extends Thread {
    private boolean running = false;

    public void run() {
        synchronized (this) {
            while (!running) {
                try {
                    wait(); // 线程等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized void wakeup() {
        running = true;
        notify(); // 唤醒线程
    }

    public static void main(String[] args) {
        MyThread_wait thread = new MyThread_wait();
        thread.start();
        thread.wakeup();
    }
}

  对于这段代码,我是展示了一个使用wait()notify()方法来实现线程间的协作的简单示例。在这个例子中,有一个MyThread_wait类,它继承自Thread类,并实现了一个简单的启动-通知模式。

代码分析
  1. MyThread_wait类中定义了一个布尔字段running,用来控制线程的执行状态。

  2. run()方法中,线程进入一个while循环,检查running变量的状态。如果runningfalse,则线程调用wait()方法进入等待状态。

  3. wait()方法会导致线程在没有其他线程调用notify()notifyAll()方法之前一直等待。当线程被唤醒时,它会跳过wait()调用后面的代码,直接继续执行循环。

  4. wakeup()方法用来设置runningtrue,并通过调用notify()唤醒在此对象监视器上等待的单个线程。如果有多个线程在等待,notify()方法会选择其中一个线程进行唤醒。

  5. main方法中,创建了MyThread_wait的一个实例,并启动了线程。然后立即调用wakeup()方法来唤醒正在等待的线程。

运行结果

  当程序运行时,MyThread_wait线程开始执行,但由于running变量初始为false,它会在run()方法中调用wait()并进入等待状态。随后,main方法中的wakeup()调用会唤醒等待的线程。线程被唤醒后,running变量被设置为true,线程将继续执行run()方法中的剩余代码。

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

注意事项
  • wait()方法必须在synchronized块或方法中调用,否则会抛出IllegalMonitorStateException异常。
  • wait()方法会导致当前线程释放对象的锁,并进入等待池等待其他线程的notify()notifyAll()调用。
  • notify()方法会随机选择一个在对象监视器上等待的线程进行唤醒,而notifyAll()会唤醒所有等待的线程。
  • 在使用wait()notify()进行线程协作时,要特别注意避免死锁和活锁的情况。

  这个示例演示了线程间的基本协作机制,是多线程编程中的一个常见模式。通过这种方式,线程可以根据条件等待或发出通知,以实现更复杂的并发控制逻辑。

线程的等待和通知

  线程的等待可以通过调用对象的wait方法实现。下面是一个示例:

/**
 * @Author ms
 * @Date 2024-04-12 19:42
 */
public class MyThread extends Thread {
    public void run() {
        synchronized (this) {
            try {
                wait(); // 线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        synchronized (thread) {
            thread.notify(); // 唤醒线程
        }
    }
}

  上述代码中,我们在MyThread类的run()方法中使用synchronized关键字来实现线程的同步,然后调用wait方法使线程等待。在Main类中创建MyThread对象,并使用synchronized关键字来实现线程的同步,然后调用notify方法来唤醒线程。

应用场景案例

  Java多线程的线程控制技术可以应用于各种场景,下面是一个简单的案例:

  假设我们有一个多线程程序,其中有一个线程负责读取网络数据,另一个线程负责处理网络数据。我们希望当读取线程读取到数据后,通知处理线程进行处理。

  我们可以使用线程的等待和通知技术来实现这个功能。在读取线程中,可以使用wait方法使线程等待,而在处理线程中,可以使用notify方法来唤醒线程。

/**
 * @Author ms
 * @Date 2024-04-12 19:42
 */
public class ReadThread extends Thread {
    public void run() {
        // 读取网络数据
        // ...

        synchronized (this) {
            notify(); // 唤醒处理线程
        }
    }
}

public class ProcessThread extends Thread {
    public void run() {
        synchronized (readThread) {
            try {
                readThread.wait(); // 线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 处理网络数据
        // ...
    }

    private ReadThread readThread; // 读取线程

    public ProcessThread(ReadThread readThread) {
        this.readThread = readThread;
    }
}

public class Main {
    public static void main(String[] args) {
        ReadThread readThread = new ReadThread();
        ProcessThread processThread = new ProcessThread(readThread);

        readThread.start();
        processThread.start();
    }
}

  上述代码中,我们定义了一个ReadThread类和一个ProcessThread类,分别用于读取网络数据和处理网络数据。在Main类中创建ReadThread对象和ProcessThread对象,并通过构造函数将它们关联起来。

优缺点分析

  Java多线程的线程控制技术有以下优点:

  • 提高程序的运行效率:通过多线程可以同时执行多个任务,提高程序的并发性和响应性。
  • 灵活性高:Java提供了多种多线程控制技术,开发人员可以根据实际需求选择合适的技术。
  • 方便调试和测试:通过合理使用线程控制技术,可以更好地控制线程的执行顺序和时间,方便调试和测试。

  但是,Java多线程的线程控制技术也存在一些缺点:

  • 复杂性较高:线程控制涉及到线程的创建、启动、睡眠和唤醒、等待和通知等多个方面,对开发人员的编程能力要求较高。
  • 容易出错:线程控制涉及到多线程并发执行,存在线程安全和竞争条件等问题,容易出现错误。

类代码方法介绍

Thread类

  • start():启动线程,使线
  • start():启动线程,使线程开始执行run()方法中的代码。
  • run():定义线程执行的任务,必须在run()方法中编写线程要执行的代码。
  • sleep(long millis):使当前线程暂停执行指定的时间(毫秒),并让出CPU给其他线程。
  • interrupt():请求中断一个线程,线程可以检查自身的中断状态,并根据需要自行处理中断。
  • isAlive():测试线程是否在活动状态,即线程已经开始且尚未完成。
  • join():使当前线程等待,直到另一个线程完成执行。
  • notify():唤醒在此对象监视器上等待的单个线程。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。

Object类(所有类都继承自Object)

  • wait():使当前线程等待,直到另一个线程调用此对象的notify()notifyAll()方法。
  • notify():唤醒在此对象监视器上等待的单个线程。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。

全文小结

  本文详细介绍了Java多线程中的线程控制技术,包括线程的创建和启动、线程的睡眠和唤醒、线程的等待和通知等。通过这些技术,我们可以创建和管理多个线程,使得程序能够并行执行多个任务,从而提高程序的运行效率和响应性。

  同时,我们也讨论了多线程编程的优点和缺点,以及如何使用Java提供的Thread类和Object类中的方法来控制线程的行为。掌握了这些知识,Java开发人员可以更加灵活和高效地处理多线程程序中的并发问题。

总结

  多线程是Java编程中的一个重要特性,它为我们提供了强大的并发处理能力。通过合理地使用线程控制技术,我们可以使程序更加高效和响应迅速。然而,多线程编程也带来了复杂性和潜在的错误,如线程安全问题和竞争条件。因此,开发人员需要仔细设计和测试多线程程序,确保程序的正确性和稳定性。

  在实际开发中,除了本文介绍的基础知识,还有许多高级的并发工具和框架,如java.util.concurrent包中的类,可以帮助我们更好地处理并发问题。不断学习和实践,深入理解多线程和并发编程的原理和技巧,对于成为一名优秀的Java开发人员至关重要。

… …

文末

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

… …

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

wished for you successed !!!


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

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

  • 29
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值