深入理解 Java 多线程、Lambda 表达式及线程安全最佳实践

Java 线程

线程使程序能够通过同时执行多个任务而更有效地运行。

线程可用于在不中断主程序的情况下在后台执行复杂的任务。

创建线程

有两种创建线程的方式。

  1. 扩展Thread类

可以通过扩展Thread类并覆盖其run()方法来创建线程:

public class MyThread extends Thread {public void run() {System.out.println("This code is running in a thread");}
}
  1. 实现Runnable接口

另一种创建线程的方式是实现Runnable接口:

public class MyRunnable implements Runnable {public void run() {System.out.println("This code is running in a thread");}
}
运行线程
  1. 扩展Thread类

如果类扩展Thread类,则可以通过创建类的实例并调用其start()方法来运行线程:

public class Main {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();System.out.println("This code is outside of the thread");}
}
  1. 实现Runnable接口

如果类实现了Runnable接口,则可以通过将类的实例传递给Thread对象的构造函数,然后调用线程的start()方法来运行线程:

public class Main {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start();System.out.println("This code is outside of the thread");}
}
区分“扩展”和“实现”线程

主要区别在于,当一个类扩展Thread类时,无法扩展任何其他类,但通过实现Runnable接口,可以扩展另一个类,例如:

class MyClass extends OtherClass implements Runnable
并发问题

因为线程与程序的其他部分同时运行,所以无法知道代码将按照什么顺序运行。当线程和主程序同时读取和写入相同的变量时,值是不可预测的。由此导致的问题称为并发问题。

示例

一个变量amount值不可预测的代码示例:

public class Main extends Thread {public static int amount = 0;public static void main(String[] args) {Main thread = new Main();thread.start();System.out.println(amount);amount++;System.out.println(amount);}public void run() {amount++;}
}

为避免并发问题,最好尽可能少地在线程之间共享属性。如果需要共享属性,一种可能的解决方案是在使用线程可以更改的任何属性之前,使用线程的isAlive()方法检查线程是否已完成运行。

示例

使用isAlive()防止并发问题:

public class Main extends Thread {public static int amount = 0;public static void main(String[] args) {Main thread = new Main();thread.start();// 等待线程完成while (thread.isAlive()) {System.out.println("Waiting...");}// 更新amount并打印其值System.out.println("Main program: " + amount);amount++;System.out.println("Main program: " + amount);}public void run() {amount++;}
}
线程池

线程池是一种管理线程的资源。它允许您创建并维护一组可重用的线程。使用线程池可以提高应用程序的性能和效率。

线程安全

线程安全是指多个线程可以访问和修改数据而不导致数据损坏。使数据线程安全的一种方法是使用同步。同步是一种机制,它允许线程一次一个地访问共享数据。

常见的线程安全问题
  • 竞态条件:当多个线程同时访问共享数据并尝试对其进行更改时,就会发生竞态条件。这可能导致数据损坏。
  • 原子性:原子操作是指不可分割的操作。当多个线程尝试同时执行原子操作时,可能会导致数据损坏。
  • 可见性:当一个线程对共享数据进行更改时,其他线程必须能够看到这些更改。
避免线程安全问题
  • 使用同步
  • 使用不可变对象
  • 使用原子操作

Java Lambda表达式

Lambda表达式简介

Lambda表达式是在Java 8中引入的。Lambda表达式是一小段代码块,它接受参数并返回一个值。Lambda表达式类似于方法,但它们不需要名称,并且可以直接在方法体中实现。

Lambda表达式的语法

最简单的Lambda表达式包含一个参数和一个表达式:

参数 -> 表达式

要使用多个参数,请将它们放在括号中:

(参数1, 参数2) -> 表达式

表达式是有限制的。它们必须立即返回一个值,并且不能包含变量、赋值或if或for等语句。为了执行更复杂的操作,可以使用带有花括号的代码块。如果Lambda表达式需要返回一个值,那么代码块应该有一个return语句。

(参数1, 参数2) -> { 代码块 }

Lambda表达式的使用

Lambda表达式通常作为参数传递给函数。在以下示例中,Lambda表达式作为参数传递给ArrayList的forEach()方法,以打印列表中的每个项:

import java.util.ArrayList;public class Main {public static void main(String[] args) {ArrayList<Integer> numbers = new ArrayList<>();numbers.add(5);numbers.add(9);numbers.add(8);numbers.add(1);numbers.forEach((n) -> { System.out.println(n); });}
}

Lambda表达式的存储

如果变量的类型是仅具有一个方法的接口,那么Lambda表达式可以存储在变量中。Lambda表达式应该具有与该方法相同数量的参数和相同的返回类型。Java内置了许多这类接口,如Consumer接口(在java.util包中),它被列表使用。

import java.util.ArrayList;
import java.util.function.Consumer;public class Main {public static void main(String[] args) {ArrayList<Integer> numbers = new ArrayList<>();numbers.add(5);numbers.add(9);numbers.add(8);numbers.add(1);Consumer<Integer> method = (n) -> { System.out.println(n); };numbers.forEach(method);}
}

Lambda表达式作为方法参数

要在方法中使用Lambda表达式,该方法应该有一个以单一方法接口作为其类型的参数。调用接口的方法将运行Lambda表达式。

interface StringFunction {String run(String str);
}public class Main {public static void main(String[] args) {StringFunction exclaim = (s) -> s + "!";StringFunction ask = (s) -> s + "?";printFormatted("Hello", exclaim);printFormatted("Hello", ask);}public static void printFormatted(String str, StringFunction format) {String result = format.run(str);System.out.println(result);}
}

Lambda表达式的优势

  • 简化代码
  • 提高可读性
  • 增强代码的表达力

Lambda 表达式是 Java 8 中引入的一项强大功能,可以简化代码并提高可读性。它们是函数式编程的重要组成部分,可以用于各种任务,例如数据处理、事件处理和流处理。

最后

为了方便其他设备和平台的小伙伴观看往期文章:

微信公众号搜索:Let us Coding,关注后即可获取最新文章推送

看完如果觉得有帮助,欢迎 点赞、收藏、关注

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

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

相关文章

AI学习笔记之六:无监督学习如何帮助人类挖掘数据金矿和防范网络欺诈

在这个大数据时代&#xff0c;企业和组织在过去几十上百年的经营过程中积累了大量的原始数据&#xff0c;其中蕴含着宝贵的商业价值和见解。然而&#xff0c;要从这些海量的、未经标记和处理的数据中发现隐藏的规律和知识&#xff0c;并不是一件容易的事情。这就好比要从一座巨…

C++实验 面向对象编程

一、实验目的&#xff1a; 掌握类中静态成员的定义方法&#xff0c;初始化方法&#xff0c;使用方法&#xff1b; 掌握类的友元说明方法&#xff0c;理解友元的使用特点 二、实验内容&#xff1a; 1、编写程序&#xff0c;统计某旅馆住宿客人的总数&#xff0c;要求输入客人…

[SaaS] AI试衣间

就刚刚&#xff01;我在淘宝用AI试了1000件衣服~淘宝AI试衣间&#xff0c;1秒换装&#xff0c;立即解锁不一样的你&#xff01;https://mp.weixin.qq.com/s/mZiNmepoWddYaLbEaap1Ow

C#入门及进阶教程| Windows编程(一)Windows应用的基本概念及开发步骤

1.Windows应用的基本概念 C#可以为Windows操作系统生成多类应用&#xff0c;其中最基本的两类应用是基于控制台的应用和基于GUI&#xff08;Graphics User Interface&#xff0c;图形用户界面&#xff09;的应用。基于控制台的应用程序的输出是基于文本的&#xff0c;不需要用…

技术资讯:Volar正式更名为Vue-Official

大家好&#xff0c;我是大澈&#xff01; 本文约700字&#xff0c;整篇阅读大约需要1分钟。 关注微信公众号&#xff1a;“程序员大澈”&#xff0c;免费加入问答群&#xff0c;一起交流技术难题与未来&#xff01; 现在关注公众号&#xff0c;免费送你 ”前后端入行大礼包“…

C语言例3-19:逻辑运算的例子

逻辑运算符的优先级&#xff1a; &#xff01; 优先于 双目运算符 优先于 关系运算符 优先于 && 优先于 ||单目逻辑运算符&#xff01; 和单目算术运算符 的优先级相同&#xff0c;结合性均是从右至左双目逻辑运算符“&&”和“||”的结合性是从左…

Android Studio实现内容丰富的安卓校园二手交易平台

获取源码请点击文章末尾QQ名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动 项目编号038 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看二手商品列表 3.查看二手商品详情 4.评论商品&…

试炼2 Marcille

文章目录 前言2D3D旋转展示动画blender工程文件头部起手式细节 前言 迷宫饭 Marcille 2D 3D 旋转展示动画 清晰展示: https://live.csdn.net/v/371218 blender工程文件 https://download.csdn.net/download/Computer_Tech/88972046 头部起手式 八点眼 侧峰线 三角鼻(三…

Java基础知识总结(3)

冒泡排序 冒泡排序是比较基础的排序算法之一&#xff0c;其思想是相邻的元素两两比较&#xff0c;较大的数下沉&#xff0c;较小的数冒起来&#xff0c;这样一趟比较下来&#xff0c;最大(小)值就会排列在一端。整个过程如同气泡冒起&#xff0c;因此被称作冒泡排序。 import…

3.AD域控如何做补丁策略?通过组策略如何做域控的补丁策略?

目录 (1)补丁简介 1.简介 2.为什么要做AD(Active Directory)统一管理电脑的补丁? (2)实战配置过程 1.实验环境介绍 第一步:新建组策略-编辑 第二步:策略应用到OU 第三步:检测是否成功 补丁策略带来的瑕疵-解决方案 解决方式: (1)补丁简介 1.简介 Wi…

显著性检验P值...

显著性检验&#xff1a;P值和置信度_显著性p<0.05,p<0.01,p<0.001-CSDN博客 看论文里面一般在结果后面都会加上 虽然学过概率统计&#xff0c;但是一直不懂在结果这里加上这个代表什么含义&#xff0c;以及如何计算&#xff0c;参考上面链接进行学习。 P值指的是比较…

springboot RestTemplate 发送xml、接收xml、pojo中的属性转为属性

背景 调用第三方接口时&#xff0c;它们的系统比较老&#xff0c;只支持接收xml而不支持json&#xff0c;默认的springboot RestTemplate不支持发送xml&#xff0c;添加依赖就可以解决这个问题。 添加jackson-dataformat-xml依赖 FasterXML/jackson-dataformat-xml是一个xml…

torchrun、 torch.distributed.launch 多节点分布式训练使用案例

数据并行分布式图: 梯度更新 分布式训练参数含义: nnodes:节点的数量,通常一个节点对应一个主机,方便记忆,直接表述为主机 node_rank:节点的序号,从0开始 nproc_per_node:一个节点中显卡的数量 -master_addr:master节点的ip地址,也就是0号主机的IP地址,该参数是…

保护数据免受.DevicData-P-XXXXXXXX勒索病毒的攻击:恢复数据的关键步骤

导言&#xff1a; 你突然发现你的电脑上出现了一个奇怪的文件扩展名&#xff0c;以“.DevicData-P-XXXXXXXX”为结尾。别慌&#xff01;你很可能中了“DevicData-P-XXXXXXXX”勒索病毒。这种病毒是一种恶意软件&#xff0c;会将你的文件加密&#xff0c;然后勒索赎金以解密它们…

Mysql中的engine

Mysql中的engine 表缺省是InnoDB类型。 修改表的引擎类型&#xff1a; ALTER TABLE tablename ENGINE MyISAM &#xff1b; 1.engine myisam MyIASM是IASM表的新版本&#xff0c;有如下扩展&#xff1a;二进制层次的可移植性。NULL列索引。对变长行比ISAM表有更少的碎片。支…

Qt学习--this指针的使用

在 C 中&#xff0c;this 指针是一个特殊的指针&#xff0c;它指向当前对象的实例。 在 C 中&#xff0c;每一个对象都能通过 this 指针来访问自己的地址。 this是一个隐藏的指针&#xff0c;可以在类的成员函数中使用&#xff0c;它可以用来指向调用对象。 当一个对象的成员…

【vim 学习系列文章 14 -- 快速选中多行】

文章目录 vim 快速选中多行的映射 vim 快速选中多行的映射 在 Vim 中&#xff0c;您可以通过定义一个映射&#xff08;map&#xff09;来快捷地在 Visual 模式下选择指定数量的行。例如&#xff0c;您可能想通过按键快速选择下面的 10 行。 以下是一个 Vim 映射示例&#xff…

实验2 芯片测试算法设计

一、【实验目的】 &#xff08;1&#xff09;理解分治策略的设计思想&#xff1b; &#xff08;2&#xff09;熟悉将伪码转换为可运行的程序的方法&#xff1b; &#xff08;3&#xff09;能够根据算法的要求设计具体的实例。 二、【实验内容】 有n片芯片&#xff0c;其中好芯片…

并发编程之 sleep 与 yield的详细解析

3.7 sleep 与 yield sleep 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态&#xff08;阻塞&#xff09; 其它线程可以使用 interrupt 方法打断正在睡眠的线程&#xff0c;这时 sleep 方法会抛出 InterruptedException public static void main(String[] args) …

基于单片机的简单温控风扇设计与实现

基于单片机的简单温控风扇设计与实现 摘要&#xff1a; 随着智能家居的兴起&#xff0c;温控设备在日常生活中扮演着越来越重要的角色。本文设计并实现了一款基于单片机的简单温控风扇系统。该系统能够根据环境温度自动调整风扇转速&#xff0c;为用户提供更加舒适的使用体验。…