Java基础-Java多线程机制

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)

目录

一、引言

二、多线程的基本概念

1. 线程与进程

2. 多线程与并发

3. 多线程的优势

三、Java多线程的实现方式

1. 继承Thread类

2. 实现Runnable接口

3. 实现Callable接口与Future

四、线程的生命周期

线程状态转换示例

五、同步与互斥

1. 同步的必要性

2. Java中的同步机制

synchronized关键字

Lock接口

volatile关键字

3. 同步的代价

六、线程间通信的深入探索

1. 等待/通知机制

2. Java并发包中的线程间通信

3. 其他并发工具


一、引言

在Java编程中,多线程机制是并发编程的核心部分,它允许程序同时执行多个任务,从而显著提高程序的执行效率和响应速度。多线程不仅在现代应用程序中广泛应用,如服务器后端处理、图形用户界面(GUI)响应、实时数据处理等场景,也是深入理解Java并发包(java.util.concurrent)和其他高级并发工具的基础。本文将从多线程的基本概念、实现方式、生命周期、同步与互斥、线程间通信、线程池等多个方面,对Java多线程机制进行深度解析,并通过代码示例进行具体说明。

二、多线程的基本概念

1. 线程与进程

  • 进程(Process):是系统进行资源分配和调度的基本单位,拥有独立的内存空间和系统资源。每个进程都包含至少一个线程,即主线程。
  • 线程(Thread):是进程中的一个执行实体,也是CPU调度和分派的基本单位。线程共享所属进程的内存空间和系统资源,但每个线程都有独立的执行栈和程序计数器。

2. 多线程与并发

  • 多线程:指在一个程序中同时执行多个线程,每个线程都有自己的执行路径和生命周期。
  • 并发:指在同一时间段内,多个任务交替执行,虽然每个时刻只有一个任务在CPU上执行,但由于CPU切换线程的速度非常快,用户感觉上多个任务在同时执行。

3. 多线程的优势

  • 提高系统响应性能:将耗时的操作放在后台线程中处理,保持主线程的流畅和响应。
  • 提高计算机资源利用率:利用多核处理器的优势,并行执行多个任务。
  • 实现异步编程:主线程可以在等待后台线程完成任务的同时,继续执行其他任务。

三、Java多线程的实现方式

1. 继承Thread类

通过继承java.lang.Thread类并重写其run方法来实现多线程。这种方式简单直接,但存在Java单继承的限制。

public class MyThread extends Thread {  @Override  public void run() {  System.out.println(Thread.currentThread().getName() + " is running.");  // 执行具体任务  }  public static void main(String[] args) {  MyThread t1 = new MyThread();  MyThread t2 = new MyThread();  t1.start(); // 启动线程  t2.start(); // 启动线程  }  
}

2. 实现Runnable接口

通过实现java.lang.Runnable接口的run方法来创建线程。这种方式更为灵活,因为一个类可以实现多个接口,同时也可以通过Thread类的构造器将Runnable实例传递给线程。

public class MyRunnable implements Runnable {  @Override  public void run() {  System.out.println(Thread.currentThread().getName() + " is running.");  // 执行具体任务  }  public static void main(String[] args) {  Thread t1 = new Thread(new MyRunnable());  Thread t2 = new Thread(new MyRunnable());  t1.start();  t2.start();  }  
}

3. 实现Callable接口与Future

Callable接口类似于Runnable,但它可以返回一个结果,并且可以抛出异常。Callable通常与Future一起使用,Future用于表示异步计算的结果。

import java.util.concurrent.*;  public class MyCallable implements Callable<Integer> {  @Override  public Integer call() throws Exception {  // 模拟耗时操作  Thread.sleep(1000);  return 123;  }  public static void main(String[] args) throws ExecutionException, InterruptedException {  ExecutorService executor = Executors.newFixedThreadPool(2);  Future<Integer> future = executor.submit(new MyCallable());  System.out.println("Waiting for result...");  Integer result = future.get(); // 阻塞等待结果  System.out.println("Result: " + result);  executor.shutdown();  }  
}

四、线程的生命周期

线程的生命周期包括新建状态、就绪状态、运行状态、阻塞状态和死亡状态。

  • 新建状态:线程被创建但尚未启动。
  • 就绪状态:线程已准备好执行,但尚未获得CPU时间片。
  • 运行状态:线程获得CPU时间片,正在执行。
  • 阻塞状态:线程由于某种原因(如等待IO操作完成、等待锁资源等)暂停执行。
  • 死亡状态:线程执行完毕或被强制终止,不再执行任何操作。

线程状态转换示例

线程的状态转换是线程执行过程中的自然流程。以下是一个简化的示例,用于说明线程状态之间的转换:

public class ThreadLifecycleExample {  static class MyThread extends Thread {  @Override  public void run() {  System.out.println(Thread.currentThread().getName() + " is in RUNNABLE state.");  synchronized (this) {  try {  wait(); // 进入WAITING状态  } catch (InterruptedException e) {  Thread.currentThread().interrupt(); // 恢复中断状态  }  }  System.out.println(Thread.currentThread().getName() + " resumes and terminates.");  }  }  public static void main(String[] args) throws InterruptedException {  MyThread t = new MyThread();  t.start(); // t进入RUNNABLE状态  // 假设主线程执行了一些操作后,决定唤醒t  Thread.sleep(1000); // 模拟耗时操作  synchronized (t) {  t.notify(); // 唤醒t,使其从WAITING状态进入RUNNABLE状态  }  // t最终会执行完毕,进入TERMINATED状态  }  
}  // 注意:上述代码中的wait()和notify()调用必须放在同步块中,否则将抛出IllegalMonitorStateException。  
// 此外,由于wait()会释放锁,而notify()不会立即让线程进入RUNNABLE状态(需要CPU调度),  
// 因此实际输出可能因线程调度和JVM实现而有所不同。

 在实际应用中,线程的状态转换远比上述示例复杂,特别是在多线程并发环境下,线程的调度和执行顺序往往难以预测。

五、同步与互斥

1. 同步的必要性

在多线程环境下,多个线程可能会同时访问共享资源(如内存中的变量、文件等),这可能导致数据不一致、脏读、脏写等问题。为了确保数据的一致性和完整性,需要对访问共享资源的操作进行同步控制。

2. Java中的同步机制

Java提供了多种同步机制,包括synchronized关键字、Lock接口及其实现(如ReentrantLock)、volatile关键字等。

synchronized关键字

  • 同步方法:在方法声明中加上synchronized关键字,该方法在同一时刻只能被一个线程执行。
  • 同步代码块:使用synchronized(Object lock) { ... }语法,对特定代码块进行同步,其中lock是锁对象。
public class Counter {  private int count = 0;  // 同步方法  public synchronized void increment() {  count++;  }  // 同步代码块  public void incrementWithBlock(Object lock) {  synchronized (lock) {  count++;  }  }  
}

Lock接口

Lock接口提供了比synchronized关键字更灵活的锁定机制,它允许显式地获取和释放锁,以及尝试非阻塞地获取锁。

import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  public class CounterWithLock {  private int count = 0;  private final Lock lock = new ReentrantLock();  public void increment() {  lock.lock(); // 显式获取锁  try {  count++;  } finally {  lock.unlock(); // 显式释放锁  }  }  
}

volatile关键字

volatile关键字用于确保变量的可见性,即当一个线程修改了被volatile修饰的变量的值时,这个新值对其他线程是立即可见的。但volatile不能保证原子性,也不具备互斥性。

public class VolatileExample {  private volatile boolean flag = false;  public void setFlag(boolean flag) {  this.flag = flag;  }  public boolean getFlag() {  return flag;  }  
}

3. 同步的代价

同步虽然能够解决多线程并发带来的问题,但它也引入了额外的开销,如线程等待锁的时间、上下文切换的成本等。因此,在设计多线程程序时,应合理使用同步机制,避免过度同步导致的性能问题。

六、线程间通信的深入探索

在Java中,线程间通信主要依赖于共享内存和相应的同步机制。通过共享内存,线程可以访问和修改同一份数据,而同步机制则确保了在多线程环境下对这些数据的访问是安全且有序的。

1. 等待/通知机制

Java中的wait()notify()/notifyAll()方法是实现线程间通信的经典方式。这些方法是Object类的一部分,因此任何对象都可以作为锁来使用这些机制。

  • wait():使当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法。调用wait()方法时,当前线程必须持有该对象的锁。调用后,当前线程会释放锁并进入等待状态,直到被唤醒。
  • notify():唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。

使用wait()notify()/notifyAll()时,必须注意以下几点:

  • 必须在同步方法或同步代码块中调用这些方法,因为它们依赖于对象锁。
  • 调用wait()的线程会释放锁,并在等待期间无法继续执行。
  • 调用notify()notifyAll()的线程不会立即释放锁,直到它退出同步方法或同步代码块。
  • wait()notify()notifyAll()在调用时必须处理InterruptedException异常。

2. Java并发包中的线程间通信

除了wait()notify()/notifyAll()方法外,Java并发包(java.util.concurrent)还提供了更高级的线程间通信机制,如BlockingQueueCountDownLatchCyclicBarrierSemaphore等。

  • BlockingQueue:支持两个附加操作的队列。这两个附加操作是:在元素从队列中取出时等待队列变为非空,以及在元素添加到队列中时等待队列中有可用空间。BlockingQueue接口是Java并发包中用于生产者-消费者问题的一种重要工具,它提供了一系列线程安全的队列操作。

BlockingQueue的实现包括ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueue等。这些实现各有特点,比如ArrayBlockingQueue是一个由数组支持的有界阻塞队列,LinkedBlockingQueue是一个由链表结构组成的有界(但默认大小为Integer.MAX_VALUE)或无界阻塞队列,而PriorityBlockingQueue则是一个支持优先级排序的无界阻塞队列。

3. 其他并发工具

  • CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
  • CyclicBarrier:一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点(common barrier point)。在涉及固定大小的线程组时,这些线程必须互相等待,直到所有线程都到达该屏障点,然后从屏障点继续执行。
  • Semaphore:一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个acquire(),然后再获取该许可。每个release()添加一个许可,从而可能释放一个正在acquire()中阻塞的线程。

这些工具各有用途,在解决复杂的并发问题时非常有用。例如,CountDownLatch可以用于等待一组任务的完成,CyclicBarrier可以用于让一组线程在某个点互相等待然后共同继续执行,而Semaphore则可以用于控制对共享资源的访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/49966.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git命令使用详细介绍

1 环境配置 设置的信息会保存在~/.gitconfig文件中 查看配置信息 git config --list git config user.name设置用户信息 git config --global user.name "有勇气的牛排" git config --global user.email “1809296387qq.com”2 获取Git仓库 2.1 本地初始化一个仓…

Android Studio入门级教程(二)——项目开发基础(Java新手向))持续更新ing

目录 前言&#xff1a; 一.使用Log工具打印日志 常见语法&#xff1a; 如何使用&#xff1f; 二.工程目录结构 三.编译配置文件build.gradle 四.运行配置文件AndroidManifest.xml 五.界面显示与逻辑处理 六.创建新的app页面 1.包含的步骤 在layout目录下创建XML文件…

uniapp集成安卓原生录屏插件以及使用

概述 我们知道UniApp的出现简化了开发者的工作流程&#xff0c;并减少了代码的重复编写。开发者可以使用一套代码编译到iOS、Android、以及各种小程序的应用&#xff0c;节省了人力和时间成本&#xff0c;但是涉及到与系统交互的时候&#xff0c;比如录屏、录音、录像、文件操…

Java 每日一题: for 与 foreach 的区别 ?

for 循环&#xff1a;是最基本的循环结构&#xff0c;可以通过初始化语句、循环条件和迭代语句来控制循环的执行。 foreach 循环&#xff08;也称为增强型 for 循环&#xff09;&#xff1a;用于遍历集合或数组中的元素&#xff0c;简化了遍历过程&#xff0c;没有显式地控制索…

vercel 如何部署 express 项目

注意&#xff1a;如果你是用 express-generator 生成的 express 项目&#xff0c;请检查是否有依赖 jade &#xff0c;如果有的话删除目录下的 views 文件夹&#xff0c;并把所有渲染页面的方法改成 res.send() !!!!!! 然后在项目根目录创建文件 vercel.json {&qu…

获取后端返回的图形验证码

如果后端返回的直接就是一个图形&#xff0c;有以下几种方式展示 一、直接在img标签里面的src里面调用接口 <img :src"dialogSrc" class"photo" alt"验证码图片" click"changeDialog">let orgUrl "/api/captcha" …

通过 WSL 2 在Windows 上挂载 Linux 磁盘

原文查看 曾为了传输或者共享不同系统的文件频繁地在 Windows 和 Linux 系统之间切换&#xff0c;效率过低&#xff0c;所以尝试通过 WSL 2 在Windows 上挂载 Linux 磁盘。 先决条件 需要在Windows 10 2004 及更高版本&#xff08;Build 19041 及更高版本&#xff09;或 Win…

基础复习(集合)

集合 Collection单列集合 1.特点 2.常用方法&#xff08;Collection都可用&#xff09; 遍历方式 迭代器遍历 Iterator<String> it c.iterator();//此处c是之前定义好的集合//第二步&#xff1a;用于判断当前位置是否有元素可以获取 //解释&#xff1a;hasNext()方…

OWS开放式耳机真的火了:漫步者、悠律、小米开放式耳机各具特点

开放式真无线耳机作为的蓝牙耳机二级分类&#xff0c;在近几年的发展趋势可以说超乎了所有人的想象。 2024 年第一季度中国线上蓝牙耳机销量达到 1757 万副,同比增长 15%,其中开放式耳机市场份额达到 14.4%,较去年同期增长 7.7%,销量同比大幅增长 148%&#xff0c;是整体耳机市…

CMakeList学习笔记

设置项目&#xff1a;project project(planning VERSION 1.0.0 LANGUAGES CXX) # 项目的名字 版本 1.1.0 编程语言 CXX 设置包含目录&#xff1a;include_directories、targer_include_directories 设置编译类型&#xff1a;add_executable、add_library add_executable(demo d…

Mysql中(基于GTID方式)实现主从复制,单主复制详细教程

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…

精密电路设计中的高精电阻:分流电阻

精密电路设计要求电路元件具有极高的精度和稳定性。在这些设计中&#xff0c;分流电阻扮演着至关重要的角色。本文将探讨分流电阻的基本原理、选择标准、应用场景以及在现代精密电路设计中的重要性。 在电子测量和控制领域&#xff0c;电流的精确测量是实现电路精确控制的关键。…

FPGA:3-8译码器的设计

1、什么是3-8译码器&#xff1f; 3-8译码器&#xff0c;顾名思义&#xff0c;三个输入&#xff0c;八个输出&#xff0c;构成3-8译码器。根据二进制特性&#xff0c;三位二进制数有八种可能&#xff0c;对应的真值表如下所示(该译码器输出低电平有效)&#xff1a; 3-8译码器(…

关于使用宝兰德bes中间件进行windows部署遇到的问题——license不存在

报错信息 日志文件中是这么报错的 遇到的具体情况&#xff1a; 实例按照**的文档手册正常步骤下去节点部署的时候没有报错&#xff0c;成功启动&#xff0c;但是日志里会有报错信息&#xff0c;也是license不存在实例创建的时候失败了&#xff0c;报错信息如下所示 解决方法…

Fork软件笔记:一键拉取仓库所有模块

Fork是一个好用的git工具&#xff0c;只是没有中文而已&#xff08;不过不用翻译也能看使用&#xff09;。 工具下载地址&#xff1a;https://fork.dev/ 界面展示&#xff1a; 当项目中仓库模块比较多时&#xff0c;可以看到每个模块都是一个分页&#xff0c;每一个都要手动切换…

ML.NET:一个.NET开源、免费、跨平台的机器学习框架

前言 今天大姚给大家分享一个.NET开源、免费、跨平台&#xff08;支持Windows、Linux、macOS多个操作系统&#xff09;的机器学习框架&#xff1a;ML.NET。并且本文将会带你快速使用ML.NET训练一个属于自己的图像分类模型&#xff0c;对图像进行分类。 ML.NET框架介绍 ML.NET…

ubuntu一些好用的开发工具及其配置

1 终端模糊搜索fzf https://github.com/junegunn/fzf 输入某命令&#xff0c;比如 conda &#xff0c;按下ctrlR&#xff0c;会显示和该命令匹配的历史命令的列表 有了这个工具再也不用记忆太复杂的命令&#xff0c;只需要知道大概几个单词&#xff0c;输入即可搜索。 其搜索…

IP地址专用SSL证书申请指南——六步完成

IP地址SSL证书是一种专门设计用于IP地址的SSL/TLS证书&#xff0c;部署IP地址SSL证书可以实现IP地址HTTPS加密。 一&#xff1a;前提条件 1&#xff1b;申请IP地址SSL证书,必须拥有这个IP地址的管理权限 2&#xff1b;非内网IP&#xff0c;以下是常见的内网IP字段 10.0.0.0…

计算机网络知识点总结————物理层

前言 一、物理层的基本概念 物理层解决什么问题 物理层的主要特性 二、传输媒体 导引型传输媒体 同轴电缆 双绞线 光纤 非导引型传输媒体 三、数据通信的基础知识 1.术语 2.编码方式 总结 前言 我站在清醒和麻木的边缘&#xff0c;不能堕落也不能解脱 一、物理层的…

鸿蒙OpenHarmony Native API【raw_dir.h与raw_file.h】 头文件

raw_dir.h Overview Related Modules: [Rawfile] Description: 提供rawfile目录相关功能 功能包括遍历和关闭rawfile目录 Since: 8 Version: 1.0 Summary Typedefs Typedef NameDescription[RawDir]typedef struct [RawDir] 提供对rawfile目录的访问 Functions Fun…