二手房交易网站排行网络工程师是什么专业

张小明 2025/12/31 22:34:06
二手房交易网站排行,网络工程师是什么专业,互联科技行业网站,做环保网站案例分析目录 一、体会线程安全问题 二、线程安全的概念 三、线程安全问题的原因 四、解决线程安全问题的方法 4.1 synchronized 关键字 一、体会线程安全问题 当我们编写一个多线程程序#xff0c;要求两个线程对同一个变量#xff08;共享变量#xff09;进行修改#xff0…目录一、体会线程安全问题二、线程安全的概念三、线程安全问题的原因四、解决线程安全问题的方法4.1 synchronized 关键字一、体会线程安全问题当我们编写一个多线程程序要求两个线程对同一个变量共享变量进行修改得到的结果是否与预期一致创建两个线程分别对共享变量count进行自增5万次操作最后输出的结果理论上应为10万但是实际上输出的结果是一个小于10万且不确定的数。读者可以自行实现一下该多线程程序运行后看看结果是否符合预期。public class Demo14_threadSafety { private static int count 0; public static void main1(String[] args) { Thread t1 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t1-结束); }); Thread t2 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t2-结束); }); t1.start(); t2.start(); // 理论上输出的结果应是100000实际输出的结果是0 // 原因是主线程 main 运行太快了当 t1 和 t2 线程还在计算时主线程已经打印结果、运行完毕了 System.out.println(count); } // 让主线程等待 t1 和 t2 线程等到它们两个都执行完成再打印故使用 join 方法 public static void main2(String[] args) throws InterruptedException { Thread t1 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t1-结束); }); Thread t2 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t2-结束); }); t1.start(); t2.start(); // 在主线程中通过 t1 和 t2 对象调用 join 方法 // 表示让主线程 main 等待 t1 线程和 t2 线程 t1.join(); t2.join(); // 当两个线程都执行完毕后主线程再继续执行打印操作 System.out.println(count); // 实际输出的结果小于100000仍不符合预期 } }二、线程安全的概念通过上面的一个例子想必读者已经体会到线程安全问题了吧那究竟什么是线程安全问题呢其原因是什么如何解决线程安全问题呢不要急且听小编慢慢道来如果在多线程环境下运行的程序其结果符合预期或与在单线程环境下运行的结果一致就说这个程序是线程安全的否则是线程不安全的。上面的例子在单线程环境下运行——比如来两个循环对共享变量进行自增操作那么结果是符合预期的但是在多线程环境下运行就不符合预期。因此该程序是线程不安全的也可以说该程序存在线程安全问题。三、线程安全问题的原因究竟是哪里出问题导致程序出现线程安全问题呢究其根本罪魁祸首是操作系统的线程调度有随机性/抢占式执行。由于操作系统的线程调度是有随机性的这就会存在这种情况某一个线程还没执行完呢就调度到其他线程去执行了从而导致数据不正确。当然了一个巴掌拍不响还有以下三个导致线程不安全的原因原子性指 Java 语句一条 Java 语句可能对应不止一条指令若对应一条指令就是原子的。可见性一个线程对主内存共享变量的修改可以及时被其他线程看到。有序性一个线程观察其他线程中指令的执行顺序由于 JVM 对指令进行了重排序观察到的顺序一般比较杂乱。因其原理与 CPU 及编译器的底层原理有关暂不讨论。之前的例子就是由于原子性没有得到保障而出现线程安全问题public static void main2(String[] args) throws InterruptedException { Thread t1 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t1-结束); }); Thread t2 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t2-结束); }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(count); }1. “count ” 这条语句对应多条指令读取数据、计算结果、存储数据。2. t1 线程和 t2 线程分别执行一次“count”语句期望的结果是“count 2”其过程如下初始情况当线程执行“count ”时总共分三个步骤load、update、save由于线程调度的随机性/抢占式执行可能会出现以下情况可能出现的情况有很多种这里只是其中一种这时候 t1 正在执行“count ”这条语句执行了“load 和 update”指令后t1 的工作内存寄存器存着更新后的值但是还未被写回内存中接着调度到 t2 线程并开始执行“count ”语句并且语句中包含的三条指令都执行。此时由于 t1 更新后的 count 的值还未写回内存因此 t2 执行 load 操作所获取到的 count 仍是 0。接着 t2 执行 update 和 save 指令当 t2 执行完成内存的 count 已被修改为 1 。此时调度回 t1 线程并继续执行 save 指令但是 t1 线程寄存器中 count 的值也是 1 此时写回内存更新后 count 的值依然是 1 。结果 count 1与预期的 count 2 不符因此存在线程安全问题其原因是操作系统的随机线程调度和 count 语句存在非原子性。四、解决线程安全问题的方法从上面的例子我们知道当一条语句的指令被拆开来执行的话是存在线程安全问题的但是当我们将“count ”这条语句的三个指令都放在一起执行怎么样当线程调度的情况如下此时 t1 线程开始执行“count ”语句的 load、update 和 save 指令。内存中的 count 为 0t1 读取到内存中的 count 之后更新至 1 并写回内存中。当 t1 执行完成后内存的 count 由 0 更新至 1接着调度至 t2 线程开始执行“count ”语句的 load、update 和 save 指令。经过更新后内存中的 count 为 1此时 t2 读取 count 并更新为 2然后写回内存中。当 t2 执行完成内存中的 count 就更新成 2 了可以发现结果与预期相符说明这个方法可行。可以将操作顺序改成先让 t1 线程完成“count ”操作再让 t2 线程完成该操作——即串行执行。现在我们对之前的例子进行优化// 可以试着让 t1 线程先执行完后再让 t2 线程执行改成串行执行 public static void main3(String[] args) throws InterruptedException { Thread t1 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t1-结束); }); Thread t2 new Thread(() - { for (int i 0; i 50000; i) { count; } System.out.println(t2-结束); }); t1.start(); t1.join(); t2.start(); t2.join(); System.out.println(count); }刚刚是让一个线程一次性执行“count ”这条语句的三个指令也就是说我们是通过这样操作将原本是非原子的三条指令打包成了一个原子指令即执行过程中不可被打断——调度走。这样就有效的解决了线程安全问题。而上述的操作其实就是 Java 中的加锁操作。当一个线程执行一个非原子的语句时通过加锁操作可以防止在执行过程中被调度走或被其他线程打断若其他线程想要执行该语句则要进入阻塞等待的状态当线程执行完毕并将锁释放操作系统这时唤醒等待中的线程才可以执行该语句。就相当于上厕所当厕所内没有人时没有线程加锁就可以使用当厕所内有人时已经有线程加锁了那么就必须等里面的人出来后才能使用。注意前一个线程解锁之后并不是后一个线程立刻获取到锁。而是需要靠操作系统唤醒阻塞等待中的线程的。若 t1、t2 和 t3 三个线程竞争同一个锁当 t1 线程获取到锁t2 线程再尝试获取锁接着 t3 线程尝试获取锁此时 t2 和 t3 线程都因获取锁失败而处于阻塞等待状态。当 t1 线程释放锁之后t2 线程并不会因为先进入阻塞状态在被唤醒后比 t3 先拿到锁而是和 t3 进行公平竞争。不遵循先来后到原则4.1 synchronized 关键字加锁 / 解锁这些操作本身是在操作系统所提供的 API 中的很多编程语言对其进行了封装Java 中使用 synchronized 关键字来进行加锁 / 解锁操作其底层是使用操作系统的mutex lock来实现的。Java 中的任何一个对象都可以用作“锁”。synchronized 锁对象{—— 进入代码块相当于加锁操作// 一些需要保护的逻辑}—— 出了代码块相当于解锁操作当多个线程针对同一个锁对象竞争的时候加锁操作才有意义。对之前的例子进行加锁操作public class Demo15_synchronized { private static int count 0; public static void main1(String[] args) throws InterruptedException { Object locker new Object(); Thread t1 new Thread(() - { for (int i 0; i 50000; i) { synchronized (locker) { count; } } System.out.println(t1-结束); }); Thread t2 new Thread(() - { for (int i 0; i 50000; i) { synchronized (locker) { count; } } System.out.println(t2-结束); }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(count); } }synchronized 关键字用来修饰普通方法时相当于给this加锁synchronized 关键字用来修饰静态方法时相当于给类对象加锁。于是可以使用另一种写法// 写法二 // 将 count 所包含的三个操作封装成一个 add 方法 // 使用 synchronized 修饰 add 方法 class Counter { private int count 0; synchronized public void add () { // synchronized 修饰普通方法相当于给 this 加锁 count; } // 相当于 // public void add () { // synchronized (this) { // count; // } // } public int get () { return count; } } public static void main(String[] args) throws InterruptedException { Counter counter new Counter(); Thread t1 new Thread(() - { for (int i 0; i 50000; i) { counter.add(); } }); Thread t2 new Thread(() - { for (int i 0; i 50000; i) { counter.add(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(counter.get()); }这样一来就成功解决了多线程程序中的线程安全问题。今天暂且到这吧~完
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

做一个静态网站多少钱免费的销售管理系统

STL缩略图完全指南:让Windows文件管理变得前所未有的简单 【免费下载链接】STL-thumbnail Shellextension for Windows File Explorer to show STL thumbnails 项目地址: https://gitcode.com/gh_mirrors/st/STL-thumbnail 还在为满屏的STL文件图标而头疼吗&…

张小明 2025/12/31 17:03:11 网站建设

四川省住房和建设厅官方网站简单的网页设计教程

月相小工具开发全解析 1. 客户端部分 月相小工具的客户端是一个基础但完整的 Web 应用,围绕单个网页构建,通过 JavaScript 实现内容的所有更改。 1.1 HTML 结构 HTML 代码相对简单,主要分为两个 div ,分别用于小工具的主视图和设置面板。以下是具体代码: <?xm…

张小明 2025/12/31 17:03:12 网站建设

网站具体流程珠海网站建设易搜互联

近日&#xff0c;小红书首座自用数据中心获得中国数据中心权威协会CDCC的2025年度十大数据优秀项目及国外数据中心媒体 w.media 的 Northeast Asia Cloud&Datacenter 年度卓悦设计&建设奖 Excellence in Data Centre Design and Build.这是国内外目前两个影响力最大的数…

张小明 2025/12/31 17:03:10 网站建设

成都做网站建设公司官网排名优化

Unix 终端使用指南:从基础到定制 1. 了解 Shell 提示符 当系统准备好运行命令时,Shell 会输出一个提示符,提示你可以输入命令。在 bash 中,默认的提示符包含计算机名称、当前目录(可能用 ~ 表示家目录)、登录名和美元符号。例如: Dave-Taylors-MacBook-Pro:~ tayl…

张小明 2025/12/31 17:03:12 网站建设

广州哪家网站建设好谷歌seo专员

简介 OpenAI最新推出的GPT-5.2模型在专业知识工作、编程能力、可靠性等方面显著提升。数据显示用户每天可节省40-60分钟&#xff0c;重度用户每周节省超10小时。新模型在电子表格建模、编程能力(SWE-Bench Pro达55.6%)、幻觉率降低30%、长文档处理、视觉理解和科学推理等方面均…

张小明 2025/12/31 17:03:13 网站建设

龙岩网站设计招聘网网站空间ftp连接失败

Markn&#xff1a;轻量级Markdown实时预览查看器&#xff0c;重塑文档阅读体验 【免费下载链接】markn Lightweight markdown viewer. 项目地址: https://gitcode.com/gh_mirrors/ma/markn 在日常文档编写和阅读中&#xff0c;你是否厌倦了在编辑器和预览模式之间频繁切…

张小明 2025/12/31 17:03:14 网站建设