Java多线程学习的关键要点和常见案例总结

news2025/6/18 5:22:06

文章目录

      • Java多线程学习的关键要点:
      • 案例示例:
    • Java多线程编程还包括更多的高级特性和实用技巧
      • 高级主题:
      • 实用案例:
      • 线程池的高级用法和配置:
      • 线程安全的最佳实践:

Java多线程学习的关键要点和常见案例总结如下:

Java多线程学习的关键要点:

  1. 线程基础概念

    • 线程(Thread)是Java程序中执行的最小单位,可以在单个进程中并发执行多个线程。
    • 线程的生命周期包括:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked/Waiting/Timed Waiting)、死亡(Terminated)等状态。
  2. 线程创建

    • 继承Thread类,重写run()方法创建线程。
    • 实现Runnable接口,将其实例传递给Thread构造函数创建线程。
    • 使用Callable接口配合FutureTaskThread创建线程,可以获取线程的返回值。
  3. 线程调度与优先级

    • Java线程有优先级设置,高优先级的线程更有可能先被执行,但这不是绝对保证,由JVM自行调度决定。
  4. 线程同步

    • synchronized关键字用于实现互斥,防止数据竞争,保护共享资源的安全访问。
    • 使用Lock接口和ReentrantLock等实现显式锁,提供了比synchronized更灵活的锁定策略。
  5. 线程间的通信与协作

    • wait(), notify()notifyAll() 方法用于线程间同步和通信。
    • CountDownLatch, Semaphore, CyclicBarrier, Exchanger 等并发工具类提供更强大的线程协作机制。
  6. 线程安全与并发容器

    • 需要保证线程安全时,可以使用Collections.synchronizedXxx()包装类或者java.util.concurrent包下的并发容器,如ConcurrentHashMapCopyOnWriteArrayList等。
  7. 线程池

    • 使用ExecutorServiceThreadPoolExecutor实现线程池,可以有效地管理和复用线程,减少创建销毁线程的开销,提供统一的并发任务提交和执行策略。

案例示例:

  1. 简单线程创建示例

    class MyThread extends Thread {
        public void run() {
            System.out.println("线程正在运行...");
        }
        
        public static void main(String[] args) {
            MyThread t = new MyThread();
            t.start();
        }
    }
    
  2. 使用Runnable接口创建线程

    class RunnableExample implements Runnable {
        @Override
        public void run() {
            System.out.println("Runnable接口创建的线程运行中...");
        }
    
        public static void main(String[] args) {
            Thread thread = new Thread(new RunnableExample());
            thread.start();
        }
    }
    
  3. 线程同步示例

    class Counter {
        private int count = 0;
        public synchronized void increment() {
            count++;
        }
    }
    
    class IncrementThread extends Thread {
        private final Counter counter;
    
        IncrementThread(Counter counter) {
            this.counter = counter;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        }
    }
    
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread thread1 = new IncrementThread(counter);
        Thread thread2 = new IncrementThread(counter);
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("最终计数:" + counter.count);
    }
    
  4. 线程池使用示例

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ThreadPoolExample {
        public static void main(String[] args) {
            ExecutorService executor = Executors.newFixedThreadPool(5);
            for (int i = 0; i < 10; i++) {
                Runnable worker = new TaskWithResult(i);
                executor.execute(worker);
            }
            executor.shutdown(); // 关闭线程池不再接收新任务
            while (!executor.isTerminated()) {
                // 等待所有任务完成
            }
            System.out.println("所有任务已完成");
        }
    }
    
    class TaskWithResult implements Runnable {
        private int taskId;
    
        public TaskWithResult(int id) {
            this.taskId = id;
        }
    
        @Override
        public void run() {
            System.out.println("线程 " + Thread.currentThread().getId() + " 正在处理任务:" + taskId);
        }
    }
    

通过这些要点和案例,学习者可以逐步掌握Java多线程编程的基本技巧和最佳实践,进而能够编写出高效、安全的并发程序。

Java多线程编程还包括更多的高级特性和实用技巧

当然,除了上面提到的内容外,Java多线程编程还包括更多的高级特性和实用技巧:

高级主题:

  1. volatile关键字

    • volatile关键字确保了共享变量的可见性和有序性,主要用于解决多线程间的内存可见性问题。
  2. 原子操作类

    • java.util.concurrent.atomic包下提供的原子操作类如AtomicIntegerAtomicLong等,它们提供了一种线程安全的、无锁的方式来更新基本类型的值。
  3. Future与FutureTask

    • Future接口表示异步计算的结果,通过它可以取消任务的执行,查询任务是否已经完成,获取结果等。
    • FutureTask实现了Future接口和Runnable接口,可以作为一个Runnable被提交到线程池执行,并能获取到线程执行结果。
  4. 线程中断

    • 通过调用Thread.interrupt()方法可以中断线程,线程应该适时检查Thread.interrupted()isInterrupted()来响应中断请求。
  5. 守护线程(Daemon Thread)

    • 守护线程是一种特殊的线程,它的特点是当所有非守护线程都结束后,JVM会自动结束守护线程,即使守护线程还在运行。
  6. 线程局部变量(ThreadLocal)

    • ThreadLocal类为每个线程维护了一个独立的副本,每个线程都可以修改自己的副本而不会影响其他线程。

实用案例:

  1. 使用Future获取线程执行结果

    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<String> future = executor.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            // 执行耗时任务
            Thread.sleep(1000);
            return "Task Result";
        }
    });
    
    // 主线程继续执行其他任务...
    // ...
    
    try {
        System.out.println("Future result: " + future.get()); // 获取线程执行结果
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    
    executor.shutdown();
    
  2. 使用volatile解决可见性问题

    class VolatileExample {
        private volatile boolean ready;
        private int number;
    
        public void prepare() {
            // 准备数据
            number = 42;
            ready = true; // 设置标志位
        }
    
        public void printNumber() {
            while (!ready) { // 当ready为true时退出循环
                Thread.yield();
            }
            System.out.println(number);
        }
    }
    
  3. 使用ThreadLocal保存线程独享数据

    public class ThreadLocalExample {
        public static final ThreadLocal<UserContext> USER_CONTEXT = new ThreadLocal<>();
    
        public static void setUserContext(UserContext context) {
            USER_CONTEXT.set(context);
        }
    
        public static UserContext getUserContext() {
            return USER_CONTEXT.get();
        }
    }
    
    // 在处理用户请求的线程中保存用户上下文
    ThreadLocalExample.setUserContext(new UserContext(userId));
    
    // 在需要的地方获取用户上下文
    UserContext userContext = ThreadLocalExample.getUserContext();
    

以上都是Java多线程编程的重要知识点和应用场景,实际使用时应根据需求选择合适的技术手段来保证程序的正确性和效率。同时,对于线程安全问题,还应充分考虑死锁、活锁、饥饿等问题,避免在并发环境中出现难以预料的问题。

线程池的高级用法和配置:

  1. 线程池的拒绝策略

    • 当线程池的任务队列满并且线程池的线程数目达到最大时,新提交的任务将会被拒绝。Java提供了四种预定义的拒绝策略:

      • AbortPolicy(默认):抛出RejectedExecutionException异常。
      • CallerRunsPolicy:调用者所在的线程执行任务。
      • DiscardPolicy:直接丢弃任务,没有任何异常信息。
      • DiscardOldestPolicy:抛弃队列中最老的任务,尝试重新提交当前任务。
    • 也可以自定义拒绝策略,实现RejectedExecutionHandler接口。

  2. 定时任务与周期任务

    • ScheduledExecutorService接口提供了定时任务和周期任务的功能,可以使用Executors.newScheduledThreadPool()创建一个定长线程池,支持定时及周期性任务执行。

    • 示例:

      ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
      
      // 延迟3秒后执行一次
      executor.schedule(new Runnable() {
          @Override
          public void run() {
              System.out.println("延迟执行的任务");
          }
      }, 3, TimeUnit.SECONDS);
      
      // 每隔2秒执行一次
      executor.scheduleAtFixedRate(new Runnable() {
          @Override
          public void run() {
              System.out.println("周期执行的任务");
          }
      }, 0, 2, TimeUnit.SECONDS);
      
      // 在程序结束前关闭线程池
      executor.shutdown();
      
  3. 线程池监控与分析

    • ThreadPoolExecutor提供了getPoolSize()getActiveCount()getCompletedTaskCount()等方法用于获取线程池状态信息。
    • 可以通过java.util.concurrent.ThreadPoolExecutorMXBean或JMX(Java Management Extensions)进行更深度的监控和管理。

线程安全的最佳实践:

  1. 不可变对象

    • 使用不可变对象可以天然地保证线程安全,因为一旦对象创建后,其状态就不会再发生变化。
  2. 并发容器

    • java.util.concurrent包下提供的并发容器,如ConcurrentHashMapCopyOnWriteArrayListBlockingQueue等,设计上即考虑到线程安全问题,因此在多线程环境下首选这些容器。
  3. 双重检查锁定(Double-Checked Locking)

    • 用于优化懒汉式单例模式的线程安全性,仅在需要实例时才进行同步操作。
  4. 细粒度锁

    • 尽可能减小锁的粒度,例如使用ReentrantReadWriteLock读写锁分离读写操作,提高并发效率。

总结:

深入学习Java多线程编程不仅要理解线程生命周期、线程创建、线程同步、线程间的通信与协作等基础概念,还需熟练掌握线程池的使用,以及如何设计和实现线程安全的代码。同时,针对特定场景选择合适的并发工具和设计模式也是提升并发程序性能的关键。在实践中不断加深对多线程的理解,并时刻注意排查和预防潜在的并发问题。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

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

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

相关文章

数字孪生10个技术栈:数据传输的四个问题

大家好&#xff0c;我是贝格前端工场&#xff0c;上期讲了数据采集的八个方式&#xff0c;数据采集之后就要进行数据的处理&#xff0c;本期继续分享&#xff0c;大家如有数字孪生或者数据可视化的需求&#xff0c;可以联络我们。 一、什么是数据处理 在数字孪生中&#xff0c…

如何配置IDEA中的JavaWeb环境(2023最新版)

创建项目 中文版&#xff1a;【文件】-【新建】-【项目】 点击【新建项目】&#xff0c;改好【名称】点击【创建】 右键自己建立的项目-【添加框架支持】&#xff08;英文版是Add Framework Support...&#xff09; 勾选【Web应用程序】-【确定】 配置tomcat 点击编辑配置 点…

【C++ 学习】拷贝构造你了解多少?

文章目录 1. 拷贝构造的引入2. 拷贝构造的引用场景 1. 拷贝构造的引入 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c;在用已存在的类类型对象创建新对象时由编译器自动调用&#xff1b; 特征&#xff1a; ① …

算法第二十五天-寻找排序数组中的最小值

寻找排序数组中的最小值 题目要求 解题思路 二分法 代码 class Solution:def findMin(self, nums: List[int]) -> int:low, high 0, len(nums) - 1while low < high:pivot low (high - low) // 2if nums[pivot] < nums[high]:high pivot else:low pivot 1re…

基于SpringBoot的医疗资源共享平台设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术 3 1.1 SpringBoot框架 3 1.2 MyBatis框架 3 1.3 WebSocket技术 4 1.4 Selenium技术 5 1.5 EL-ADMIN技术 5 1.6 Ajax技术 5 1.7 本章小结 6 2 系统分析 7 2.1 功能需求分析 7 2.2 非功能需求 9 2.3 本章小结 10 3 系统设计 11 3.…

【Python】专栏文章索引

为了方便 快速定位 和 便于文章间的相互引用等 作为一个快速准确的导航工具 Python 目录&#xff1a; &#xff08;一&#xff09;装饰器函数 &#xff08;二&#xff09;牛客网—软件开发-Python专项练习 &#xff08;三&#xff09;time模块

工地安全反光衣穿戴监测报警摄像机

工地安全反光衣穿戴监测报警摄像机是为了提高工地施工人员的安全意识和监管效率而设计的。这种设备结合了反光衣、监测系统和报警摄像机的功能&#xff0c;可以有效减少工地事故的发生。 首先&#xff0c;工地安全反光衣是一种具有高度可见度的服装&#xff0c;能够使穿戴者在夜…

【漏洞复现】Salia PLCC cPH2 远程命令执行漏洞(CVE-2023-46359)

0x01 漏洞概述 Salia PLCC cPH2 v1.87.0 及更早版本中存在一个操作系统命令注入漏洞&#xff0c;该漏洞可能允许未经身份验证的远程攻击者通过传递给连接检查功能的特制参数在系统上执行任意命令。 0x02 测绘语句 fofa&#xff1a;"Salia PLCC" 0x03 漏洞复现 ​…

【AI视野·今日NLP 自然语言处理论文速览 第八十四期】Thu, 7 Mar 2024

AI视野今日CS.NLP 自然语言处理论文速览 Thu, 7 Mar 2024 Totally 52 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers The Heuristic Core: Understanding Subnetwork Generalization in Pretrained Language Models Authors Adith…

vulhub中Weblogic < 10.3.6 ‘wls-wsat‘ XMLDecoder 反序列化漏洞(CVE-2017-10271)复现

Weblogic的WLS Security组件对外提供webservice服务&#xff0c;其中使用了XMLDecoder来解析用户传入的XML数据&#xff0c;在解析的过程中出现反序列化漏洞&#xff0c;导致可执行任意命令。 访问http://your-ip:7001/即可看到一个404页面&#xff0c;说明weblogic已成功启动 …

【精选好刊】JCR2区SCI仅17天上线见刊,最后10篇版面!

录用案例 JCR2区地质环境类SCI&EI (进展顺) 【期刊简介】IF&#xff1a;3.0-4.0&#xff0c;JCR2区&#xff0c;中科院3/4区&#xff1b; 【检索情况】SCI&EI双检&#xff1b; 【征稿领域】地球观测、环境监测和管理相关或结合研究均可&#xff1b; 【案例分享】重…

基于范围的for循环(C++11)和auto

auto C11中&#xff0c;标准委员会赋予了auto全新的含义即&#xff1a; auto不再是一个存储类型指示符&#xff0c;而是作为一个新的类型 指示符来指示编译器&#xff0c;auto声明的变量必须由编译器在编译时期推导而得。 int a 10;auto b a;auto c a;auto d TestAuto(…

线性dp+中位数,POJ3666 Making the Grade

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 3666 -- Making the Grade (poj.org) 二、解题报告 1、思路分析 先不考虑…

YOLO水稻虫害识别数据集(16类,近一万张图像)

YOLO水稻虫害识别数据集&#xff0c;包含稻秆蝇、二化螟、褐飞虱、蓟马、蛴螬、蝼蛄等常见害虫&#xff0c;共16个水稻害虫类别&#xff0c;9700多张图像&#xff0c;yolo标注完整&#xff0c;全部原始数据&#xff0c;未应用增强。 适用于CV项目&#xff0c;毕设&#xff0c;科…

vue2 vue-cli vue-router vuex

Vue2 插值表达式 利用表达式进行插值渲染&#xff0c;将数据渲染到页面中。 语法&#xff1a;{{ 表达式 }} PS&#xff1a; 使用的数据要存在支持的是表达式&#xff0c;不是语句 if、for不能在标签属性中使用{{ }} v-show和v-if v-show底层原理&#xff1a;切换css的dis…

L-2:插松枝(Python)

作者 陈越 单位 浙江大学 人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上&#xff0c;做成大大小小的松枝。他们的工作流程&#xff08;并不&#xff09;是这样的&#xff1a; 每人手边有一只小盒子&#xff0c;初始状态为空。每人面前有用不完的松枝干和一个推送…

Ainx的消息封装

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于Ainx系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系列…

300分钟吃透分布式缓存-25讲:Redis是如何处理容易超时的系统调用的?

BIO 线程简介 Redis 在运行过程中&#xff0c;不可避免的会产生一些运行慢的、容易引发阻塞的任务&#xff0c;如将内核中的文件缓冲同步到磁盘中、关闭文件&#xff0c;都会引发短时阻塞&#xff0c;还有一些大 key&#xff0c;如一些元素数高达万级或更多的聚合类元素&#…

CNN中的参数,计算量,FLOPs,Multi-Add(乘加),输出特征图尺寸和通道变化

在阅读论文时&#xff0c;我们会遇到参数量&#xff0c;FLOPS&#xff0c;Multi-add&#xff0c; CNN参数&#xff0c;CNN计算量等概念&#xff0c;通过阅读整理&#xff0c;这篇博客希望以最简洁的解释帮助大家理解这些基本概念。 首先&#xff0c;我们看一下卷积的计算方式&a…

【Linux】编译器-gcc/g++使用

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 前言2. 初见gcc和g3. 程序的翻译过程3.1 预处理3.1.1 宏替换 去注释 头文件展开3.1.2 条件编译 3.2 编译3.3 汇编3.4 链接 4. 链接4.1 动态链接4.2 静态链接 1. 前言 在之…