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

java面试题-并发基础

1.多线程的出现是要解决什么问题的? 本质什么?

  1. 提高程序性能:单线程程序只能按照固定的顺序依次执行每个任务,无法同时处理多个任务。多线程技术可以在同一时间内执行多个任务,从而提高程序的运行效率和响应速度。

  1. 提高程序的并发性:单线程程序在处理多个任务时,需要等待某个任务完成后才能进行下一个任务,导致程序无法同时处理多个请求。多线程技术可以同时处理多个请求,提高程序的并发性。

  1. 充分利用多核CPU:现代计算机大多都具备多核CPU,但是单线程程序只能利用其中的一个核心,无法充分利用CPU的性能。多线程技术可以同时使用多个CPU核心,充分利用计算机的性能。

  1. 程序设计的灵活性:多线程技术可以将程序拆分成多个独立的任务,每个任务可以独立进行设计和测试,从而提高程序的灵活性和可维护性。

多线程的本质是通过将程序拆分成多个线程并行执行,实现程序的并发执行,从而提高程序的效率和性能。同时,多线程也带来了一些问题,如线程安全性、死锁、竞争条件等,需要仔细考虑和处理。

2.Java是怎么解决并发问题的?

Java提供了多种机制来解决并发问题,包括锁、原子变量、线程池、并发集合等等。其中最常用的机制包括synchronized关键字、volatile关键字、以及并发集合类如ConcurrentHashMap、ConcurrentLinkedQueue等。

  1. synchronized关键字

synchronized关键字可以保证同一时刻只有一个线程可以访问被synchronized修饰的代码块或方法,从而避免多个线程同时访问同一个共享资源,导致数据不一致或者线程安全问题。synchronized关键字可以用于方法、代码块、静态方法等。

  1. volatile关键字

volatile关键字可以确保在多线程环境下变量的可见性和有序性,从而避免了由于指令重排等原因导致的线程安全问题。使用volatile关键字修饰的变量在每次被访问时,都会从内存中读取最新的值,而不是从缓存中读取,保证了变量的可见性。

  1. 原子变量

Java提供了原子变量类如AtomicInteger、AtomicLong等,这些类提供了一些线程安全的操作,如自增、自减、比较并交换等操作。使用原子变量可以避免多线程同时修改同一个变量导致的线程安全问题。

  1. 线程池

线程池是一种重用线程的机制,可以减少线程创建和销毁的开销。Java提供了Executor框架来支持线程池的使用。通过使用线程池,可以减少线程的创建和销毁次数,从而提高了程序的执行效率。

  1. 并发集合类

Java提供了一系列的并发集合类,如ConcurrentHashMap、ConcurrentLinkedQueue等,这些集合类可以在多线程环境下保证线程安全,从而避免了使用传统的集合类时可能出现的线程安全问题。

  1. JMM

Java内存模型(Java Memory Model,简称JMM)是Java用来描述多线程访问共享内存时,内存可见性、指令重排、原子性等特性的规范。Java通过JMM来保证多线程之间的可见性、有序性和原子性,从而避免了线程安全问题。

综上所述,Java通过提供锁、原子变量、线程池、并发集合等机制以及JMM规范来解决并发问题,从而保证了多线程环境下程序的正确性和安全性。

3.线程安全有哪些实现思路?

线程安全的实现思路主要有以下几种:

  1. 互斥同步

互斥同步是通过锁来保证多个线程之间的互斥访问,从而避免多个线程同时访问共享资源导致的数据不一致或者线程安全问题。常见的互斥同步机制包括synchronized关键字、Lock接口等。

  1. 非阻塞同步

非阻塞同步是一种无需线程阻塞等待的同步方式,通过CAS操作等原子性操作来保证线程之间的互斥访问,从而避免了线程阻塞等待的开销。Java中的Atomic类就是基于非阻塞同步的机制。

  1. 读写同步

读写同步是一种针对读写操作进行区分的同步方式,通过读写锁来实现多个线程之间的并发读取、独占写入,从而提高程序的执行效率。Java中的ReentrantReadWriteLock就是一个典型的读写锁。

  1. 信号量

信号量是一种多线程同步机制,通过信号量来控制同时访问共享资源的线程数,从而实现线程之间的同步。Java中的Semaphore类就是一种基于信号量的同步机制。

  1. ThreadLocal

ThreadLocal是一种线程本地变量,它可以为每个线程提供独立的变量副本,从而避免多个线程之间共享变量导致的线程安全问题。ThreadLocal的实现原理是为每个线程维护一个独立的变量副本,从而保证线程之间互不干扰。

  1. 并发容器

Java提供了一些并发容器类,如ConcurrentHashMap、ConcurrentLinkedQueue等,这些容器类可以在多线程环境下保证线程安全,从而避免了使用传统的容器类时可能出现的线程安全问题。

综上所述,实现线程安全的方式有很多种,可以根据具体的应用场景来选择最合适的实现方式。

4.如何理解并发和并行的区别?

并发是指一个处理器同时处理多个任务。

并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。

5.线程有哪几种状态? 分别说明从一种状态到另一种状态转变有哪些方式?

  1. 新建(New):当一个线程对象被创建但还没有开始运行时,它的状态就是新建状态。

  1. 就绪(Runnable):当一个线程处于就绪状态时,表示它已经准备好了,等待系统的调度程序分配CPU时间片段,以便开始执行它的run()方法。

  1. 运行(Running):当一个线程正在执行run()方法时,它的状态就是运行状态。

  1. 阻塞(Blocked):当一个线程因为某些原因暂时停止执行,以等待系统资源或者等待某个条件得到满足,此时它的状态就是阻塞状态。

  1. 等待(Waiting):当一个线程因为某些条件没有得到满足而处于等待状态时,它的状态就是等待状态。在等待状态下,线程不会占用CPU资源,直到其它线程调用notify()或notifyAll()方法来唤醒它。

  1. 计时等待(Timed Waiting):当一个线程处于计时等待状态时,它会等待一定的时间,或者等待某个条件被满足,直到时间到期或者条件被满足时才会被唤醒。

  1. 终止(Terminated):当一个线程的run()方法执行完毕,或者因为出现了异常而结束时,它的状态就是终止状态。

一个线程在不同状态之间转换的方式有以下几种:

  1. 新建状态转变为就绪状态:通过调用start()方法来启动线程,使它进入就绪状态。

  1. 就绪状态转变为运行状态:当系统调度程序把CPU时间片段分配给了线程,使它开始执行run()方法时,线程就从就绪状态转变为运行状态。

  1. 运行状态转变为就绪状态:当一个线程的run()方法执行完毕或者调用了wait()方法,使它暂时停止执行时,它就从运行状态转变为就绪状态。

  1. 运行状态转变为阻塞状态:当一个线程因为某些原因而暂停执行,如等待某个条件得到满足时,它就从运行状态转变为阻塞状态。

  1. 阻塞状态转变为就绪状态:当等待的条件得到满足或者等待时间到期时,线程就从阻塞状态转变为就绪状态。

  1. 运行状态、就绪状态、阻塞状态、等待状态转变为终止状态:当一个线程的run()方法执行完毕,或者因为出现了异常而结束时,它的状态就会转变为终止状态。

6.通常线程有哪几种使用方式?

  1. 基于继承Thread类:通过继承Thread类,重写其run()方法来创建线程,并调用start()方法启动线程。例如:

public class MyThread extends Thread {@Overridepublic void run() {// 线程执行的代码}
}MyThread thread = new MyThread();
thread.start();
  1. 实现Runnable接口:通过实现Runnable接口,并将其实例作为Thread的构造函数参数来创建线程。例如:

public class MyRunnable implements Runnable {@Overridepublic void run() {// 线程执行的代码}
}Thread thread = new Thread(new MyRunnable());
thread.start();
  1. 实现Callable接口:与实现Runnable接口类似,但是Callable接口的call()方法可以返回执行结果,并且可以抛出异常。例如:

public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {// 线程执行的代码return "result";}
}FutureTask<String> task = new FutureTask<>(new MyCallable());
Thread thread = new Thread(task);
thread.start();
  1. 使用线程池:通过线程池可以有效地管理线程的生命周期,避免频繁地创建和销毁线程。例如:

ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(new MyRunnable());
executor.submit(new MyCallable());
executor.shutdown();

7.线程的中断方式有哪些?

线程的中断方式主要有以下三种:

  1. 通过调用interrupt()方法:这种方式是最常见的中断线程的方式。调用线程的interrupt()方法会将线程的中断状态设置为true,但并不会中断线程的执行。在线程的执行代码中,需要不断地检查线程的中断状态,如果中断状态为true,则可以结束线程的执行。

  1. 通过检查isInterrupted()方法:可以在线程的执行代码中使用isInterrupted()方法来检查线程的中断状态,如果中断状态为true,则可以结束线程的执行。与interrupt()方法不同,调用isInterrupted()方法不会改变线程的中断状态。

  1. 通过使用stop()方法:stop()方法可以立即结束线程的执行,但是这种方式已经被废弃,不建议使用。在使用stop()方法时,线程可能会被中断在执行过程中的任意位置,导致数据不一致和资源泄露等问题。

需要注意的是,使用interrupt()方法和isInterrupted()方法时,需要在线程的执行代码中不断地检查线程的中断状态,以便及时地结束线程的执行。同时,在使用这两种方式中断线程时,需要注意处理InterruptedException异常,以便正确地维护线程的中断状态。

8.线程之间有哪些协作方式?

  1. wait()和notify()/notifyAll()方法:可以使用wait()方法让一个线程等待,直到其他线程调用notify()或notifyAll()方法唤醒它。以下是一个简单的例子:

public class WaitNotifyExample {public static void main(String[] args) {Object lock = new Object();Thread t1 = new Thread(() -> {synchronized (lock) {try {System.out.println("Thread 1 waiting");lock.wait();System.out.println("Thread 1 notified");} catch (InterruptedException e) {e.printStackTrace();}}});Thread t2 = new Thread(() -> {synchronized (lock) {System.out.println("Thread 2 notifying");lock.notify();}});t1.start();t2.start();}
}

在上面的例子中,t1线程调用了lock的wait()方法,导致它被阻塞,直到t2线程调用了lock的notify()方法。在t2线程调用notify()方法之后,t1线程就会被唤醒,继续执行。

  1. join()方法:可以使用join()方法让一个线程等待另一个线程执行完成,再继续执行。以下是一个简单的例子:

public class JoinExample {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {try {Thread.sleep(1000);System.out.println("Thread 1 finished");} catch (InterruptedException e) {e.printStackTrace();}});Thread t2 = new Thread(() -> {try {Thread.sleep(2000);System.out.println("Thread 2 finished");} catch (InterruptedException e) {e.printStackTrace();}});t1.start();t2.start();t1.join();t2.join();System.out.println("All threads finished");}
}

在上面的例子中,主线程启动了t1和t2两个线程,然后调用了它们的join()方法,等待它们执行完成。当t1和t2两个线程都执行完成后,主线程才会继续执行。

相关文章:

java面试题-并发基础

1.多线程的出现是要解决什么问题的? 本质什么?提高程序性能&#xff1a;单线程程序只能按照固定的顺序依次执行每个任务&#xff0c;无法同时处理多个任务。多线程技术可以在同一时间内执行多个任务&#xff0c;从而提高程序的运行效率和响应速度。提高程序的并发性&#xff…...

用纯C语言实现3D空间中的点坐标转化为屏幕二维点坐标,包含主视图、侧视图、俯视图、正等轴投影

要实现3D空间中的点坐标转换为屏幕二维点坐标&#xff0c;需要进行透视变换和投影变换。以下是一些基本的思路和示例代码&#xff0c;可以用于实现主视图、侧视图、俯视图、正等轴投影。 1. 主视图投影 主视图投影是指以一个点作为视点&#xff0c;从一个方向观察物体&#x…...

.sh脚本文件的执行方式

方法1&#xff1a; ./xxx.sh方法2&#xff1a; source xxx.sh方法3&#xff1a; bash xxx.sh方法4: sh xxx.sh初识shell&#xff0c;学习并记录...

Android 基础知识4-2.5View与VIewGroup的概念、关系与区别

1.概念&#xff1a; Android里的图形界面都是由View和ViewGroup以及他们的子类构成的&#xff1a; View&#xff1a;所有可视化控件的父类,提供组件描绘和时间处理方法 ViewGroup&#xff1a; View类的子类&#xff0c;可以拥有子控件,可以看作是容器 Android UI中的控件都是…...

【ESP 保姆级教程】玩转巴法云篇① ——初识巴法云

忘记过去,超越自己 ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-02-19 ❤️❤️ 本篇更新记录 2023-02-19 ❤️🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请…...

Python学习-----模块3.0(正则表达式-->re模块)

目录 前言&#xff1a; 导入模块 1.re.match() 函数 &#xff08;1&#xff09;匹配单个字符 &#xff08;2&#xff09;匹配多个字符 (3) 匹配开头和结尾 2.re.search() 函数 3.re.findall() 函数 4.re.finditer() 函数 5.re.split() 函数 6.re.sub() 函数 7.re.sub…...

JSP中http与内置对象学习笔记

本博文讲述jsp客户端与服务器端的http、jsp内置对象与控制流和数据流实现 1.HTTP请求响应机制 HTTP协议是TCP/IP协议中的一个应用层协议&#xff0c;用于定义客户端与服务器之间交换数据的过程 1.1 HTTP请求 HTTP请求由请求行、消息报头、空行和请求数据4部分组成。 请求行…...

Windows Server 2016远程桌面配置全过程

镜像下载 系统镜像网址 本次下载的是 Windows Server 2016 (Updated Feb 2018) (x64) - DVD (Chinese-Simplified) 远程桌面配置 Step 1 在开始菜单搜索服务&#xff0c;打开服务器管理器&#xff0c;点击右上角的管理按钮 Step 2 添加角色控制&#xff0c;点击下一步 S…...

SPI通讯简介

一、基本概念 SPI是串行外设接口(Serial Peripheral Interface)的缩写&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;主要应用在EEPROM,FLASH,实时时钟&#xff0c;AD转换器&#xff0c;多MCU间通讯等等&#xff0c;SPI端口可以在多主器件…...

Python 迭代器

迭代器协议 对象必须提供一个 next() 方法&#xff0c;执行该方法要么迭代下一项&#xff0c;要么就引起一个 StopIteration异常以终止迭代&#xff08;只能往后不能往前&#xff09;—— 迭代器协议 协议是一种约定&#xff0c;可迭代对象实现了迭代器协议&#xff08;for、…...

Python语言零基础入门教程(二十七)

Python OS 文件/目录方法 Python语言零基础入门教程&#xff08;二十六&#xff09; 61、Python os.utime() 方法 概述 os.utime() 方法用于设置指定路径文件最后的修改和访问时间。 在Unix&#xff0c;Windows中有效。 语法 utime()方法语法格式如下&#xff1a; os.uti…...

Redis基础操作以及数据类型

目录 Redis基础操作 java中的i是不是原子操作&#xff1f;不是 数据类型 1. list 2. set 3. Hash哈希 4. Zset有序集合 Redis基础操作 set [key] [value] 设置值 &#xff08;设置相同的会将原先的覆盖&#xff09; get [key] 获取值 不能覆盖和替换 ttl [key] 以秒为单…...

自抗扰控制ADRC之反馈控制律(NLSEF)

目录 前言 1.非线性状态误差反馈控制律(NLSEF) 1.1 控制律形式 1.2 控制量的生成(或者说扰动的补偿) 1.2.1补偿形式① 1.2.1补偿形式② 2.仿真分析 2.1仿真模型 2.2仿真结果 前言 前面的两篇博客依次介绍了TD微分跟踪器安排过渡过程、扩张观测器&#xff1a; 自抗扰…...

“生成音乐“ 【循环神经网络】

前言 本文介绍循环神经网络的进阶案例&#xff0c;通过搭建和训练一个模型&#xff0c;来对钢琴的音符进行预测&#xff0c;通过重复调用模型来进而生成一段音乐&#xff1b; 使用到Maestro的钢琴MIDI文件 &#xff0c;每个文件由不同音符组成&#xff0c;音符用三个量来表示…...

能否手写vue3响应式原理-面试进阶

&#xff08;二&#xff09;响应式原理 利用ES6中Proxy作为拦截器&#xff0c;在get时收集依赖&#xff0c;在set时触发依赖&#xff0c;来实现响应式。 &#xff08;三&#xff09;手写实现 1、实现Reactive 基于原理&#xff0c;我们可以先写一下测试用例 //reactive.spe…...

前端工程师leetcode算法面试必备-简单的二叉树

一、前言 本难度的题目主要考察二叉树的基本概念和操作。 1、基本概念 树是计算机科学中经常用到的一种非线性数据结构&#xff0c;以分层的形式存储数据。二叉树是一种特殊的树结构&#xff0c;每个节点最多有两个子树&#xff0c;通常子树被称作“左子树”和“右子树”。 …...

【什么程度叫熟悉linux系统】

一、编译内核 1、Linux系统背景&#xff1a;Ubuntu 2、内核源码kernel.org进行下载 3、解压内核源文件linux-6.1.12.tar.xz、命令&#xff1a;tar -xvf linux-6.1.12.tar.xz 4、进入解压好的文件inux-6.1.12 5、配置内核命令&#xff1a;make menuconfig&#xff08;需要进…...

编译安装MySQL

MySQL 5.7主要特性 随机root 密码&#xff1a;MySQL 5.7 数据库初始化完成后&#xff0c;会自动生成一个 rootlocalhost 用户&#xff0c;root 用户的密码不为空&#xff0c;而是随机产生一个密码。原生支持&#xff1a;Systemd 更好的性能&#xff1a;对于多核CPU、固态硬盘、…...

Kubernetes一 Kubernetes之入门

二 Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点&#xff1a;不能为应…...

SQLServer2000 断电后数据库suspect“置疑”处理

SQLServer2000 断电后数据库suspect“置疑”处理 背景介绍&#xff1a; 前些天加班时候&#xff0c;接到小舅子微信&#xff0c;说一个客户的winXP 机器上sql2000的数据库在断电重启后&#xff0c;数据库执行命令时提示suspect“置疑”错误。小舅子电子工程师&#xff0c;对数…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...