面试题004-Java-Java多线程(下)

news2024/7/6 19:32:27

面试题004-Java-Java多线程(下)

这里写目录标题

  • 面试题004-Java-Java多线程(下)
    • 题目自测
    • 题目答案
      • 1. synchronized 关键字的作用?
      • 2. volatile 关键字的作用?
      • 3. synchronized 和 volatile 的区别?
      • 4. synchronized 和 ReentrantLock 的区别?
      • 5. ThreadLocal有什么用?
      • 6. 线程池有什么用?为什么不推荐使用内置线程池?
      • 7. 如何自定义线程池?
      • 8. Java线程池有哪些参数?阻塞队列有几种?拒绝策略有几种?
      • 9. 线程池处理任务的流程了解吗?
      • 10. 如何给线程池命名?为什么建议给线程池命名?
    • 参考资料

题目自测

  • 1. synchronized 关键字的作用?
  • 2. volatile 关键字的作用?
  • 3. synchronized 和 volatile 的区别?
  • 4. synchronized 和 ReentrantLock 的区别?
  • 5. ThreadLocal有什么用?
  • 6. 线程池有什么用?为什么不推荐使用内置线程池?
  • 7. 如何自定义线程池?
  • 8. Java线程池有哪些参数?阻塞队列有几种?拒绝策略有几种?
  • 9. 线程池处理任务的流程了解吗?
  • 10. 如何给线程池命名?为什么建议给线程池命名?

题目答案

1. synchronized 关键字的作用?

答:在Java中synchronized关键字用于实现线程同步,主要解决是多个线程之间访问相同资源不会发生数据不一致的问题。它可以作用于方法或代码块上,以保证同一时间只有一个线程可以执行被同步的方法或代码块。

  • 同步实例方法: 表示该方法在同一时间只能由一个线程访问同一个实例。

    public class SynchronizedExample {
        public synchronized void synchronizedMethod() {
            // 同步代码
        }
    }
    
  • 同步静态方法:表示该方法在同一时间只能由一个线程访问同一个类的所有实例。

    public class SynchronizedExample {
        public static synchronized void synchronizedStaticMethod() {
            // 同步代码
        }
    }
    
  • 同步代码块:表示该代码块在同一时间只能由一个线程访问该对象。

    public class SynchronizedExample {
        private final Object lock = new Object();
    
        public void synchronizedBlock() {
            synchronized (this) {
                // 同步代码
            }
        }
    }
    

2. volatile 关键字的作用?

答:在Java中volatile关键字用于声明变量的可见性和防止指令重排,从而提供一种轻量级的同步机制。
在可见性方面,用volatile修饰的变量,来确保一个线程对该变量的修改对其他线程立即可见。
在防止指令重排方面,volatile会禁止JVM对变量操作的指令进行重新排序。

3. synchronized 和 volatile 的区别?

答:synchronized和volatile两个关键字都用于实现线程同步的机制。

  • volatile是线程同步的轻量级实现,volatile性能比synchronized要好。volatile关键字只能用于变量,而synchronized关键字可以修饰方法和代码块。
  • volatile能保证数据的可见性,但不能保证数据的原子性。synchronized两者都能保证。
  • volatile主要解决变量在多个线程之间的可见性,而synchronize解决的是多个线程之间访问资源的同步性。

4. synchronized 和 ReentrantLock 的区别?

答:synchronized和ReentrantLock都是Java中用于实现线程同步的机制,并且都是可重入锁。

  • synchronized:
    • 是Java语言的内置关键字,用于对代码块或方法进行同步。
    • 简单易用,直接在方法或代码块上使用即可。
    • 由JVM实现,使用方便,但功能较为有限。
  • ReentrantLock:
    • ReentrantLock是java.util.concurrent.locks包中的类,提供了更灵活和丰富的锁机制(响应中断、尝试获取锁、使用条件变量等)。
    • 需要显示的加锁和解锁,通过代码来控制锁的获取和释放。
    • 由Java库实现,功能强大,灵活性高。

5. ThreadLocal有什么用?

答:ThreadLocal在Java中用于创建线程局部变量,确保每个变量都有自己的独立副本变量,从而避免多线程共享一个变量带来的线程安全问题,同时提高了并发性能。然而在使用ThreadLocal时需要注意内存泄露问题,由于ThreadLocal变量的生命周期与线程线相同,如果线程池中线程长时间不被销毁,而ThreadLocal变量没有被正确移除,可能会导致内存泄露问题,因此建议在不再使用ThreadLocal变量时显示调用remove()方法。
它的使用场景有用户会话管理、数据库连接管理、事物管理等。

6. 线程池有什么用?为什么不推荐使用内置线程池?

答:Java中的线程池是一种基于池化技术设计用于执行异步任务的框架,它维护了一定数量的线程,避免频繁地创建和销毁线程带来的性能开销和资源浪费。他的主要作用是提高资源复用、提高系统稳定性、便于管理和提供灵活的并发策略。

不推荐使用内置线程池的主要原因是内置线程池等配置选项有限、不能满足所有的应用场景的需求。Java库中提供了几种预定义线程的实现,如Executors类中的newFixedThreadPoolnewCacheThreadPoolnewSingleThreadExecutor等。

  • FixedThreadPool 和 SingleThreadExecutor 使用无界队列(LinkedBlockingQueue),在任务提交速度超过执行速度时,任务队列可能无限增长,导致内存耗尽。
  • CacheThreadPool 使用无界线程池,在高并发下可能会创建大量线程、导致系统资源耗尽。未被回收的线程可能会长时间占用资源,造成线程泄漏问题。

7. 如何自定义线程池?

答:在Java中,自定义线程池可以通过ThreadPoolExecutor类来实现。ThreadPoolExecutor提供了丰富的配置选项,如核心线程数(corePoolSize)、最大线程数(maximumPoolSize)、任务队列(workQueue)和拒绝策略(rejectedExecutionHandler)等,可以根据具体需求进行灵活配置。

import java.util.concurrent.ArrayBlockingQueue;  
import java.util.concurrent.ThreadPoolExecutor;  
import java.util.concurrent.TimeUnit;  
  
public class CustomThreadPoolExample {  
  
    public static void main(String[] args) {  
        // 核心线程数 :线程池在空闲时保留的线程数,即使没有任务需要处理。
        int corePoolSize = 5;  
        // 最大线程数 :线程池允许创建的最大线程数。
        int maximumPoolSize = 10;  
        // 非核心线程空闲存活时间 :当线程数超过核心线程数时,多余的空闲线程的存活时间。
        long keepAliveTime = 1L;  
        // 时间单位 : 空闲线程存活时间的时间单位。
        TimeUnit unit = TimeUnit.SECONDS;  
        // 任务队列 :用于保存等待执行任务的队列。
        ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);  
        // 线程工厂 : 用于创建新线程。
        ThreadFactory threadFactory = Executors.defaultThreadFactory();  
        // 拒绝策略 : 当线程池和队列都满时,如何处理新任务
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();  
  
        // 创建ThreadPoolExecutor  
        ThreadPoolExecutor executor = new ThreadPoolExecutor(  
                corePoolSize,  
                maximumPoolSize,  
                keepAliveTime,  
                unit,  
                workQueue,  
                threadFactory,  
                handler  
        );  
  
        // 提交任务  
        for (int i = 0; i < 15; i++) {  
            int taskId = i;  
            executor.execute(() -> {  
                System.out.println(Thread.currentThread().getName() + " is processing " + taskId);  
                try {  
                    // 模拟任务执行时间  
                    Thread.sleep(1000);  
                } catch (InterruptedException e) {  
                    Thread.currentThread().interrupt();  
                }  
            });  
        }  
  
        // 关闭线程池(不再接受新任务,但已提交的任务会继续执行)  
        executor.shutdown();  
  
        // 等待所有任务完成  
        while (!executor.isTerminated()) {  
            // 等待一段时间  
        }  
  
        System.out.println("All tasks completed.");  
    }  
}

8. Java线程池有哪些参数?阻塞队列有几种?拒绝策略有几种?

答:
线程池的参数

  • corePoolSize(核心线程数):线程池中始终保留的线程数量,即使这些线程处于空闲状态。
  • maximumPoolSize(最大线程数):线程池中允许创建的最大线程数量。当任务队列已满且当前线程数小于最大线程数时,会创建新线程来处理任务。
  • keepAliveTime(空闲线程存活时间):当线程池中的线程数超过核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
  • timeUnit(时间单位):keepAliveTime 参数的时间单位。常见值包括 TimeUnit.SECONDS、TimeUnit.MILLISECONDS 等。
  • workQueue(任务队列):用于保存等待执行任务的队列l。
  • threadFactory(线程工厂):用于创建新线程。
  • rejectedExecutionHandler(拒绝策略):当线程池和队列都满时,如何处理新任务。

阻塞队列

  • ArrayBlockingQueue:一个基于数组的有界阻塞队列。按FIFO(先进先出)顺序保存任务。
  • LinkedBlockingQueue:一个基于链表的可选有界阻塞队列。通常用于无限制的任务队列。
  • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等待一个相应的移除操作。
  • PriorityBlockingQueue:一个基于优先级的无限阻塞队列。任务按照优先级顺序执行。
  • DelayQueue:一个基于优先级队列的无界阻塞队列,只有在延迟期满时才能从队列中取走元素。

拒绝策略

  • AbortPolicy(默认策略):抛出 RejectedExecutionException 异常,阻止系统正常工作。
  • CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务。这种策略会降低新任务的提交速度,从而减轻线程池的负载。
  • DiscardPolicy:直接丢弃任务,不抛出异常。如果允许任务丢失,这种策略可以用于避免系统过载。
  • DiscardOldestPolicy:丢弃队列中最旧的任务(即即将执行的任务),然后重新尝试提交新任务。

9. 线程池处理任务的流程了解吗?

答:线程池处理任务的流程可以总结为:提交任务、检查核心线程数、任务队列处理、非核心线程创建、执行任务以及线程回收。

  1. 通过submit()或execute()方法提交任务
  2. 检查核心线程数,如果当前线程数少于核心线程数,那么就创建新的核心线程来执行任务。如果当前线程数已达到核心线程数,将任务放入任务队列。
  3. 如果任务队列没有满,将任务队列继续放入队列。如果任务队列已满,检查当前线程数是否小于最大线程数。
  4. 如果当前线程数小于最大线程数,创建新的非核心线程执行任务,如果当前线程已经达到了最大线程数,执行拒绝策略。
  5. 线程从任务队列取出任务执行。
  6. 线程池中的非核心线程在完成任务后不会立即销毁,进入保持存活状态,只有当这些线程在空闲时间超过keepAliveTime后被回收。

10. 如何给线程池命名?为什么建议给线程池命名?

答:要给线程池中的线程命名,可以自定义一个 ThreadFactory,在创建线程时设置线程名称。

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程工厂,它设置线程名称,有利于我们定位问题。
 */
public final class NamingThreadFactory implements ThreadFactory {

    private final AtomicInteger threadNum = new AtomicInteger();
    private final String name;

    /**
     * 创建一个带名字的线程池生产工厂
     */
    public NamingThreadFactory(String name) {
        this.name = name;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setName(name + " [#" + threadNum.incrementAndGet() + "]");
        return t;
    }
}

在 Java 中,为线程池中的线程命名是一种良好的实践。命名线程有助于调试和监控,使得可以轻松识别和跟踪线程的行为和状态。

参考资料

  • JavaGuide
  • 牛客网-Java面试宝典

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

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

相关文章

filex文件系统功能预研

filex资源 filex的源码路径有两个&#xff1a; 一个是azure-rtos下的filex&#xff1a;azure-rtos/filex (github.com)一个是eclipse-threadx下的filex&#xff1a;eclipse-threadx/filex filex的文档地址&#xff1a;rtos-docs/rtos-docs/filex 第三方文档&#xff1a;Thre…

搭建知识付费系统的技术框架与实现路径

知识付费系统已经成为内容创作者和企业变现的重要工具。要成功搭建一个高效、稳定、用户体验良好的知识付费系统&#xff0c;明确技术框架和实现路径至关重要。本文将详细解析搭建知识付费系统的技术框架&#xff0c;并提供具体的实现路径和相关技术代码示例。 一、知识付费系…

大陆ARS548使用记录

一、Windows连接上位机 雷达是在深圳路达买的&#xff0c;商家给的资料中首先让配置网口&#xff0c;但我在使用过程中一直出现无法连接上位机的情况。接下来说说我的见解和理解。 1.1遇到的问题 按要求配置好端口后上位机无连接不到雷达&#xff0c;但wireshark可以正常抓到数…

基于改进YOLOv5s的跌倒行为检测 | 引入SKAttention注意机制 + 引入空间金字塔池化结构SPPFCSPC + 结合ASFF自适应空间融合

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。为了实现电厂人员跌倒行为的实时检测&#xff0c;防止跌倒昏迷而无法及时发现并救援的事件发生&#xff0c;针对跌倒行为检测实时性以及特征提取能力不足的问题&#xff0c;提出了一种改进YOLOv5s的跌倒行为检测算法网络&a…

公网IP变更自动微信通知与远程执行命令的C++开源软件

基本功能 智能公网IP变更监测与微信通知 一旦检测到公网IP地址发生变更&#xff0c;系统将自动通过预设的QQ邮箱&#xff08;该邮箱与微信绑定&#xff0c;实现微信通知&#xff09;发送新IP地址通知。同时&#xff0c;软件会即时更新本地配置文件中的IP地址及变更时间&#…

MySQL Server使用

MySQL Server MySQL Server基本操作查看数据库服务命令行连接&#xff08;这些操作都可以在workbench中进行&#xff09; MySQL Server基本操作 MySQL基础&#xff1a;安装卸载与配置 查看数据库服务 电脑–管理–管理和应用程序–服务–MySQL80 命令行连接&#xff08;这…

Linux线程:编织并发的梦幻世界

目录 &#x1f6a9;引言 &#x1f6a9;听故事&#xff0c;引概念 &#x1f6a9;生产者消费者模型 &#x1f680;再次理解生产消费模型 &#x1f680;挖掘特点 &#x1f6a9;条件变量 &#x1f680;条件变量常用接口 &#x1f680;条件变量的原理 &#x1f6a9;引言 上一篇…

HQChart报价列表高级应用教程7-走势列数据对接

HQChart报价列表高级应用教程7-走势列数据对接 走势列小程序效果图PC效果图HQChart代码地址走势列类型配置走势列数据格式示例走势列 单独使用一列显示每个股票的走势图 小程序效果图 PC效果图 HQChart代码地址 地址:github.com/jones2000/HQChart

医院挂号系统:基于JSP和MySQL的现代化医疗预约平台

开头语&#xff1a;您好&#xff0c;我是专注于医疗系统开发的IT学长。如果您对医院挂号系统感兴趣&#xff0c;欢迎联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术&#xff0c;B/S架构 工具&#xff1a;Eclipse&#xff0c;MyEclips…

大模型对汽车行业意味着什么?_汽车企业大模型

引 言 大模型是一种利用海量数据进行训练的深度神经网络模型&#xff0c;其特点是拥有庞大的参数规模和复杂的计算结构。通过在大规模数据集上进行训练&#xff0c;大模型能够学习到丰富的模式和特征&#xff0c;从而具备强大的泛化能力&#xff0c;可以对未知数据做出准确的预…

10 - matlab m_map地学绘图工具基础函数 - 绘制多边形区域、流线图、散点图和添加注释的有关函数

10 - matlab m_map地学绘图工具基础函数 - 绘制多边形区域、流线图、散点图和添加注释的有关函数 0. 引言1. 关于m_patch2. 关于m_streamline3. 关于m_scatter4. 关于m_annotation5. 结语 0. 引言 本篇介绍下m_map中绘制多边形区域函数&#xff08;m_patch&#xff09;、绘制流…

Landsat数据从Collection1更改为Collection2

目录 问题解决 问题 需要注意!您使用的是废弃的陆地卫星数据集。为确保功能持续&#xff0c;请在2024年7月1日前更新。 在使用一些以前的代码时会遇到报错&#xff0c;因为代码里面用的是老的数据集 解决 对于地表反射率SR&#xff0c;需要在name中&#xff0c;将C01换为C02&…

Mysql-基础-DDL操作

1、数据库操作 查询 查询所有数据库 show databases; 创建 创建数据库 create database [if not exists] 数据库名 使用及查询 use 数据库名 select database() 查询当前所处数据库 删除 drop database [if not exists] 数据库名 2、表操作 查询当前库中的所…

SpringBoot源码阅读3-启动原理

SpringBootApplication public class DistApplication {public static void main(String[] args) {// 启动入口SpringApplication.run()SpringApplication.run(DistApplication.class, args);} }1、服务构建 这里"服务"指的是SpringApplication对象&#xff0c;服务…

安防视频监控/视频汇聚EasyCVR平台国标GB28181级联上级平台,视频无法播放是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可提供7*24小时实时高清视频监控、云端录像、云存储、录像检索与回看、智能告警…

24位DAC转换的FPGA设计及将其封装成自定义IP核的方法

在vivado设计中,为了方便的使用Block Desgin进行设计,可以使用vivado软件把自己编写的代码封装成IP核,封装后的IP核和原来的代码具有相同的功能。本文以实现24位DA转换(含并串转换,使用的数模转换器为CL4660)为例,介绍VIVADO封装IP核的方法及调用方法,以及DAC转换的详细…

【postgreessql 】统计库中的所有表数量

在PostgreSQL中&#xff0c;你可以使用SQL查询来统计数据库中的所有表数量。这通常涉及到查询系统目录表&#xff0c;特别是 pg_catalog.pg_tables 表&#xff0c;它存储了关于数据库中所有表的信息。 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema IN …

游戏冻结工具 -- 雪藏HsFreezer v1.78

软件简介 HsFreezer是一款多功能游戏冻结工具&#xff0c;它允许用户随意暂停和继续游戏&#xff0c;同时具备系统优化和进程管理的功能。这款软件特别适合希望在游戏加载时间节省或在游戏与其他任务之间快速切换的用户。其主要特点包括快捷键操作、单锁模式的丝滑切换&#x…

【大数据】StarRocks的系统架构

StarRocks 架构简洁&#xff0c;整个系统的核心只有 FE&#xff08;Frontend&#xff09;、BE (Backend) 或 CN (Compute Node) 两类进程&#xff0c;方便部署与维护&#xff0c;节点可以在线水平扩展&#xff0c;元数据和业务数据都有副本机制&#xff0c;确保整个系统无单点。…

数据大小端问题

文章目录 大小端前言函数引用(接下来使用此函数对高低位进行切换)先看截取的对于大小端的定义大小端数据的直观理解[重点] 对uchar数组进行取操作定义一个uint8_t的数组观察起内部内存尝试使用uint32_t 每次区 1、2、3、4byte数据 提升经过上面的介绍一定对大小端有了一定的了解…