码出高效:Java开发手册笔记(线程安全)

这篇具有很好参考价值的文章主要介绍了码出高效:Java开发手册笔记(线程安全)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

    并发与并行的目标都是尽可能快地执行完所有任务。以医生坐诊为例,某个科室有两个专家同时出诊,这就是两个并行任务,其中一个医生,时而问诊,时而查看化验单,然后继续问诊,突然又中断去处理病人的咨询,这就是并发。在并发环境下,由于程序的封闭性全被打破,出现了以下特点:
    ( 1 )并发程序之间有相互制约的关系。 直接制约体现为一个程序需要另一个程序的计算结果;间接制约体现为多个程序竞争共享资源,如处理器、缓冲区等。
    ( 2 )并发程序的执行过程是断断续续的。 程序需要记忆现场指令及执行点。
    ( 3 )当并发数设置合理并且 CPU 拥有足够的处理能力时,并发会提高程序的运行效率。

线程安全

    线程可以拥有自己的操作栈、程序计数器、局部变量表等资源,它与同一进程内的其他线程共享该进程的所有资源。线程在生命周期内存在多种状态。如图 7-2 所示 ,有 NEW (新建状态)、 RUNNABLE (就绪状态)、 RUNNING (运行状态)、BLOCKED (阻塞状态)、 DEAD (终止状态)五种状态。
码出高效:Java开发手册笔记(线程安全)
    ( 1 ) NEW ,即新建状态,是线程被创建且未启动的状态。 创建线程的方式有三种:第一种是继承自 Thread 类,第二种是实现 Runnable 接口,第三种是实现 Callable 接口。相比第一种,推荐第二种方式,因为继承自 Thread 类往往不符合里氏代换原则,
而实现 Runnable 接口可以使编程更加灵活,对外暴露的细节比较少,让使用者专注于实现线程的 run()方法上。第三种Callable 接口的 call() 声明如下:

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

    由此可知,Callable 与 Runnable 有两点不同:第一,可以通过 call()获得返回值。前两种方式都有一个共同的缺陷,即在任务执行完成后 ,无法直接获取执行结果 , 需要借助共享变量等获取 ,而 Callable 和 Future 则很好地解决了这个问题;第二,call()可以抛出异常。而 Runnable 只有通过 setDefaultUncaughtExceptionHandler()的方式才能在主线程中捕捉到子线程异常。
示例:
Car类实现Runnable接口

package com.example.demo.test;

/**
 * @Author: Ron
 * @Create: 2023-04-21 14:38
 */
public class Car implements Runnable {

    @Override
    public void run() {
        int i = 1/0;
        System.out.println("Car");
    }
}

Airplane实现Callable接口

package com.example.demo.test;

import java.util.concurrent.Callable;

/**
 * @Author: Ron
 * @Create: 2023-04-28 14:18
 */
public class Airplane implements Callable {
    @Override
    public Object call() throws Exception {

        int i = 1/0;
        System.out.println("Airplane");
        return i;
    }
}

    ( 2 ) RUNNABLE ,即就绪状态 ,是调用start()之后运行之前的状态。线程的start()不能被多次调用,否则会抛出IllegalStateException 异常。
    ( 3 ) RUNNING ,即运行状态 , 是 run()正在执行时线程的状态。线程可能会由于某些因素而退出 RUNNING ,如时间、异常、锁、调度等。
    ( 4 ) BLOCKED ,即阻塞状态 , 进入此状态 , 有以下种情况。

  • 同步阻塞:锁被其他线程占用。
  • 主动阻塞:调用 Thread 的某些方法,主动让出 CPU 执行权 ,比如 sleep()、join()等。
  • 等待阻塞:执行了 wait()。

    ( 5 ) DEAD ,即终止状态,是 run() 执行结束,或同异常退出后的状态 , 此状态不可逆转。
    再用医生坐诊的例子说明 , 医生并发地处理多个病人的询问、开化验单、查看化验结果、开药等工作,任何一个环节一旦出现数据混淆,都可能引发严重的医疗事故。延伸到计算机的线程处理过程中,因为各个线程轮流占用 CPU 的计算资源,可能会出现某个线程尚未执行完就不得不中断的情况,容易导致线程不安全。例如,在服务端某个高并发业务共享某用户数据,首先 A 线程执行用户数据的查询任务 , 但数据尚未返回就退出 CPU 时间片;然后 B 线程抢占了 CPU 资源执行并覆盖了该用户数据 ,最后 A 线程返回到执行现场,直接将 B 线程处理过后的用户数据返回给前端,导致页面显示数据错误。为保证线程安全,在多个线程并发地竞争共享资源时,通常采用同步机制协调各个线程的执行,以确保得到正确的结果。

    线程安全问题只在多线程环境下才出现,单线程串行执行不存在此问题。保证高并发场景下的线程安全,可以从以下四个维度考量:
    ( 1 )数据单线程内可见。单线程总是安全的。通过限制数据仅在单线程内可见,可以避免数据被其他线程篡改。最典型的就是线程局部变量,它存储在独立虚拟机栈帧的局部变量表中,与其他线程毫无瓜葛。 ThreadLocal 就是采用这种方式来实现线程安全的。
    ( 2 )只读对象。只读对象总是安全的。它的特性是允许复制、拒绝写人。最典型的只读对象有 String 、 Integer 等。一个对象想要拒绝任何写人,必须要满足以下条件:使用 final 关键字修饰类,避免被继承;使用 private final 关键字避免属性被中途修改;没有任何更新方法;返回值不能可变对象为引用。
    ( 3 )线程安全类。某些线程安全类的内部有非常明确的线程安全机制。比如StringBuffer 就是一个线程安全类,它采用synchronized 关键字来修饰相关方法。
    ( 4 )同步与锁机制。如果想要对某个对象进行并发更新操作,但又不属于上述三类,需要开发工程师在代码中实现安全的同步机制。虽然这个机制支持的并发场景很有价值,但非常复杂且容易出现问题。
    线程安全的核心理念就是“要么只读,要么加锁”。合理利用好 JDK 提供的并发包,往往能化腐朽为神奇。 Java 并发包( java.util.concurrent ,JUC ) 中大多数类注释都写有@author Doug Lea。如果说 Java 是一本史书,那么 Doug Lea 绝对是开疆拓土的伟大人物。 Doug Lea 在当大学老师时,专攻并发编程和并发数据结构设计,主导设计了JUC 并发包,提高了 Java 并发编程的易用性,大大推进了 Java 的商用进程。并发包主要分成以下几个类族:
    ( 1 )线程同步类。这些类使线程间的协调更加容易,支持了更加丰富的线程协调场景,逐步淘汰了使用 Object 的 wait()和 notify()进行同步的方式。主要代表为CountDownLatch 、 Semaphore 、 CyclicBarrier 等。
    ( 2 )并发集合类。集合并发操作的要求是执行速度快,提取数据准。最著名的类非 ConcurrentHashMap 莫属,它不断地优化,由刚开始的锁分段到后来的 CAS,不断地提升并发性能。其他还有 ConcurrentSkipListMap、 CopyOnWriteArrayList、
BlockingQueue 等。
    ( 3 )线程管理类。虽然 Thread 和 ThreadLocal 在 JDK1.0 就已经引入,但是真正把 Thread 发扬光大的是线程池。根据实际场景的需要,提供了多种创建线程池的快捷方式,如使用 Executors 静态工厂或者使用 ThreadPoolExecutor 等。另外,通过
ScheduledExecutorService 来执行定时任务。
    ( 4 )锁相关类。锁以 Lock 接口为核心,派生出在一些实际场景中进行互斥操作的锁相关类。最有名的是 ReentrantLock。锁的很多概念在弱化,是因为锁的实现在各种场景中已经通过类库封装进去了。
    并发包中的类族有很多,差异比较微妙,开发工程师需要有很好的 Java 基础、逻辑思维能力,还需要有定的数据结构基础,才能够彻底分清各个类族的优点、缺点及差异点。
    解决线程安全问题的能力是开发工程师进阶的重要能力之一。由于初创公司的业务流量通常比较小,再加上其初级程序员缺乏线程安全意识。所以,即使出现了由高并发导致的错误,往往也由于复现难度大、追踪困难而不了了之。但是在后期的系统重构中,这些公司一定会为以上线程安全隐患买单。文章来源地址https://www.toymoban.com/news/detail-473995.html

到了这里,关于码出高效:Java开发手册笔记(线程安全)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ⚡️⚡️Java多线程编程的高效、安全实践

    博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客👦🏻 《java 面试题大全》 🍩惟余辈才疏学浅,临摹之作或有不妥之处,还请读者海涵指正。☕🍭 《MYSQL从入门到精通》数据库是开发者必会基础之一~ 🪁 吾期望此文有资助于尔,即使粗浅难及深广,亦备添少许微薄

    2024年02月14日
    浏览(34)
  • Java并发编程学习笔记(一)线程的入门与创建

    认识 程序由指令和数据组成,简单来说,进程可以视为程序的一个实例 大部分程序可以同时运行多个实例进程,例如记事本、画图、浏览器等 少部分程序只能同时运行一个实例进程,例如QQ音乐、网易云音乐等 一个进程可以分为多个线程,线程为最小调度单位,进程则是作

    2024年02月16日
    浏览(39)
  • 阿里Java开发手册~安全规约

    1. 【强制】隶属于用户个人的页面或者功能必须进行权限控制校验。 说明: 防止没有做水平权限校验就可随意访问、修改、删除别人的数据,比如查看他人的私信 内容、修改他人的订单。 2. 【强制】用户敏感数据禁止直接展示,必须对展示数据进行脱敏。 说明: 查看个人

    2024年02月15日
    浏览(33)
  • 瑞_Java开发手册_(四)安全规约

    🙊前言:本文章为瑞_系列专栏之《Java开发手册》的安全规约篇。由于博主是从阿里的《Java开发手册》学习到Java的编程规约,所以本系列专栏主要以这本书进行讲解和拓展,有需要的小伙伴可以点击链接下载。本文仅供大家交流、学习及研究使用,禁止用于商业用途,违者

    2024年01月17日
    浏览(36)
  • 码出高效_第一章 | 有意思的二进制表示及运算

    设想有8条电路,每条电路有高电平和低电平两种状态,即就有2 8 =256种不同的信号。假设其表示区间为0~255,最大数即2 8 -1。 那么32条电路能够表示最大数为(2 32 -1)=4294967295,即所谓的32位电路信号。 正负数表示: 上面的8条电路,最左侧一条表示正负:0-整数,1-负数,不

    2024年02月06日
    浏览(25)
  • 【JAVA开发面试】如何处理并发访问如何进行代码的单元测试Java多线程编程消息中间件设计模式技术难题是如何解决的

    【 点我-这里送书 】 本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题 中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明

    2024年02月03日
    浏览(39)
  • Java并发编程详解:实现高效并发应用的关键技术

    在当前的计算机领域,高效的并发编程对于Java开发人员而言变得越发重要。作为流行的编程语言,Java提供了强大的并发编程支持,使开发人员能够充分发挥多核处理器和线程的潜力,构建高性能、高吞吐量的应用程序。本文将深入探讨Java并发编程的关键技术,包括线程安全

    2024年02月13日
    浏览(34)
  • 【并发编程】多线程安全问题,如何避免死锁

    从今天开始阿Q将陆续更新 java并发编程专栏 ,期待您的订阅。 在系统学习线程之前,我们先来了解一下它的概念,与经常提到的进程做个对比,方便记忆。 线程和进程是操作系统中的两个重要概念,它们都代表了程序运行时的执行单位,它们的出现是为了更好地管理计算机

    2024年02月11日
    浏览(36)
  • 【JavaEE】并发编程(多线程)线程安全问题&内存可见性&指令重排序

    目录 第一个问题:什么是线程安全问题? 第二个问题:为什么会出现线程安全问题?  第三个问题:如何解决多线程安全问题?  第四个问题:产生线程不安全的原因有哪些?  第五个问题:内存可见性问题及解决方案  第六个问题:指令重排序问题? 线程安全就是多线程

    2024年02月01日
    浏览(53)
  • 关于并发编程与线程安全的思考与实践

    作者:京东健康 张娜 并发编程的意义是充分的利用处理器的每一个核,以达到最高的处理性能,可以让程序运行的更快。而处理器也为了提高计算速率,作出了一系列优化,比如: 1、硬件升级:为平衡CPU 内高速存储器和内存之间数量级的速率差,提升整体性能,引入了多

    2024年02月03日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包