当前位置: 首页 > news >正文 企业做网站哪家网站好基础建设审计网站 news 2025/11/4 19:49:42 企业做网站哪家网站好,基础建设审计网站,装修设计图纸效果图,seo自动发布外链工具前言#xff1a;多线程编程已经广泛开始使用#xff0c;其可以充分利用系统资源来提升效率#xff0c;但是线程安全问题也随之出现#xff0c;它直接影响了程序的正确性和稳定性#xff0c;需要对其进行深入的理解与解决。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解… 前言多线程编程已经广泛开始使用其可以充分利用系统资源来提升效率但是线程安全问题也随之出现它直接影响了程序的正确性和稳定性需要对其进行深入的理解与解决。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 在正式开始讲解之前先让我们看一下本文大致的讲解内容 目录 1.线程不安全概念及其原因 2.原子性问题 3.可见性问题 4.指令重排序问题 5.线程不安全的解决方案 1synchronized关键字 补充synchronized关键字的可重入性 2volatile关键字 1.线程不安全概念及其原因 在多线程编程中线程安全是一个至关重要的概念当多个线程同时访问和操作共享数据时如果没有适当的同步机制可能会导致程序出现意想不到的结果。 下面通过一个简单的代码示例来观察线程不安全现象 // 此处定义一个int类型的变量 private static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {// 对count变量进行自增5w次for (int i 0; i 50000; i) {count;}});Thread t2 new Thread(() - {// 对count变量进行自增5w次for (int i 0; i 50000; i) {count;}});t1.start();t2.start();// 如果没有这俩join肯定不行的。线程还没自增完就开始打印了。很可能打印出来的count值小于预期t1.join();t2.join();// 预期结果应该是10wSystem.out.println(count: count); } 在上述代码中我们创建了两个线程 t1 和 t2它们都试图对共享变量 count 进行大量的自增操作理论上当两个线程都完成任务后count 的值应该达到100000。然而实际运行结果却常常小于这个预期值读者可以复制代码在编译器中自行尝试一下这便是典型的线程不安全现象。 ——那么为何会出现这种情况呢原因有如下两个 线程调度的随机性线程调度是由操作系统掌控的它会在多个线程之间随机地切换执行权。在上述代码场景中t1 和 t2 线程极有可能交替执行自增操作。例如t1 线程读取了 count 的当前值假设为0但在执行自增操作count之前线程调度器暂停了 t1 线程并切换到 t2 线程。此时t2 线程同样读取到 count 的值为0随后执行自增操作将 count 的值更新为1。接着t1 线程恢复执行可它依然使用之前读取到的0进行自增操作最终将 count 的值更新为1而非预期的2。 多个线程修改同一变量当多个线程同时对同一个共享变量进行写操作且没有任何同步保障时数据的不一致性便极易出现在当前例子中t1 和 t2 都在对 count 变量进行修改它们的操作相互干扰最终致使结果出现偏差。 至此我们通过上述的讲解我们就大致的了解了到底什么是多线程中的线程不安全以及产生线程不安全的原因了。 2.原子性问题 在多线程中除了上述我们讲解的当我们有多个线程同时对同一个数据进行操作从而引起的线程安全问题外原子性问题也是可能引起线程不安全的原因那么什么是原子性问题呢 原子性的概念 原子性从本质上讲是指一个操作或者一组操作作为一个不可分割的整体其执行过程要么全部成功完成要么全部不执行绝不存在被其他线程中断的中间状态。在多线程环境中倘若一个操作不具备原子性那么就极有可能出现部分执行的状况进而导致数据错误。 这里我们还是使用上述的两个线程各自增加count5w次的例子来进行讲解这里再让我们看一下上述的代码 // 定义一个共享的int类型变量count并初始化为0 private static int count 0;public static void main(String[] args) throws InterruptedException {// 创建第一个线程t1其任务是对count进行50000次自增操作Thread t1 new Thread(() - {for (int i 0; i 50000; i) {count;}});// 创建第二个线程t2同样对count进行50000次自增操作Thread t2 new Thread(() - {for (int i 0; i 50000; i) {count;}});// 启动线程t1t1.start();// 启动线程t2t2.start();// 调用t1线程的join方法确保t1线程执行完毕t1.join();// 调用t2线程的join方法确保t2线程执行完毕t2.join();// 预期count的值应该是100000但实际结果往往并非如此System.out.println(count: count); } 在上述代码中的 count 操作看似简单的自增指令实际上并非原子操作在Java语言中count 大致可分解为以下三个步骤 首先读取 count 的当前值。 接着将读取到的值加1。 最后将计算后的新值写回 count。 假设 t1 和 t2 线程同时执行 count 操作就可能出现如下情形t1 线程读取了 count 的初始值为0然而在执行加1操作之前线程调度器切换到了 t2 线程。t2 线程同样读取到 count 的值为0随后进行加1操作并将结果1写回 count此时count 的值变为1接着t1 线程恢复执行它依旧使用之前读取到的0进行加1操作得到结果1并将其写回 count。 如此一来最终 count 的值仅增加了1而非预期的2。这便是因为 count 操作不具备原子性在执行过程中被其他线程中断从而导致了错误的结果。 ——这就是所谓的原子性问题。 3.可见性问题 在了解完上述的两种造成多线程中的线程安全问题的原因之后在让我们看一下另一种造成多线程线程安全的原因——内存可见性问题 ——那么什么是内存可见性问题可见性问题呢 可见性的概念 可见性简单来说是指一个线程对共享变量值的修改能够及时且准确地被其他线程察觉到。在多线程编程的情境下如果一个线程修改了共享变量的值但是其他线程无法立即获取到这个修改后的最新值那么就会产生可见性问题。 当然提到内存可见性问题就不得不提及Java内存模型那么Java内存模型和内存可见性问题又有什么联系呢 Java内存模型与可见性问题的关系 Java内存模型JMM明确规定了Java程序中变量的访问规则。每个线程都拥有自己独立的工作内存当线程需要读取一个共享变量时会首先将变量从主内存拷贝到自己的工作内存然后再从工作内存中读取数据而当线程要修改一个共享变量时会先在工作内存中修改其副本之后再将修改后的值同步回主内存。 由于每个线程的工作内存相互独立这就可能导致一种情况一个线程修改了共享变量的值但这个修改尚未及时同步到主内存或者其他线程还未从主内存更新自己工作内存中的副本从而致使其他线程无法看到该变量的最新值。 这样我们就大致的了解了什么是Java内存模型以及Java内存模型与可见性问题的关系了。 我相信读者在看到这里的时候脑子里只用一个想法我勒个去上边这都是什么和什么啊根本看不懂啊没关系接下来让我们使用一个例子来帮助你更好的理解上述内存可见性问题。 案例代码 static class Counter {public int flag 0; }public static void main(String[] args) {Counter counter new Counter();Thread t1 new Thread(() - {while (counter.flag 0) {// 线程t1在此处循环等待直到flag的值变为非0}System.out.println(循环结束!);});Thread t2 new Thread(() - {Scanner scanner new Scanner(System.in);System.out.println(输入一个整数:);counter.flag scanner.nextInt();});t1.start();t2.start(); } 在这个例子中t1 线程在一个循环里持续检查 counter.flag 的值是否为0如果是则持续循环等待t2 线程等待用户输入一个整数并将其赋值给 counter.flag。按照预期当用户输入非0的值时t1 线程应当结束循环并打印 循环结束!。 然而实际情况可能是即便 t2 线程已经修改了 counter.flag 的值t1 线程却并未立即察觉到这个变化依旧在循环中持续等待。这是因为 t1 线程可能始终在使用自己工作内存中的 counter.flag 副本而没有及时从主内存更新该副本从而引发了可见性问题。 至此我相信读者通过上述的案例讲解之后就对内存可见性问题有了进一步理解了 4.指令重排序问题 讲解完上述三种产生多线程问题的原因之后还有没有其他的可能产生多线程线程安全的原因呢还真有其就是指令重排序问题。 指令重排序的概念 指令重排序是指编译器或处理器为了优化程序的性能在不改变单线程程序语义的前提下对指令的执行顺序进行重新排列。在单线程环境中指令重排序通常不会引发问题因为程序的执行结果是确定的。然而在多线程环境下指令重排序可能会改变代码的执行顺序进而导致线程安全问题。 这里我们也是使用一个案例来帮助读者来进一步理解指令重排序问题。 // 定义两个共享变量 private static boolean initialized false; private static int value;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {value 42;initialized true;});Thread t2 new Thread(() - {if (initialized) {System.out.println(value: value);}});t1.start();t2.start();t1.join();t2.join(); } 在这个例子中t1 线程首先对 value 赋值为42随后将 initialized 设置为 true。t2 线程则检查 initialized 的值如果为 true就打印 value 的值。由于指令重排序的存在t1 线程中的指令可能会被重新排序。 例如initialized true 可能会在 value 42 之前执行。这样一来当 t2 线程检查 initialized 的值为 true 时value 的值可能还未被正确赋值从而导致打印出错误的结果可能是0而不是42。 这样我们就了解了什么是指令重排序问题了。 5.线程不安全的解决方案 学习完上述可能产生线程安全的原因之后接下来就让我们学习一下如何去在多线程编程中防止程序发生线程安全问题。 1synchronized关键字 在学习如何使用synchronized关键字之前先让我们看一下synchronized关键字是什么 synchronized 关键字具有强大的互斥特性。当一个线程进入一个对象的 synchronized 方法或代码块时其他线程若试图进入同一个对象的 synchronized 方法或代码块将会被阻塞等待直到持有锁的线程释放锁为止。 这里我们使用一个例子来进行讲解 public class Demo2 {public static int number 0;public static void main(String[] args) throws InterruptedException {Object locker new Object();Thread thread1 new Thread(() - {for (int i 0; i 1000; i) {synchronized (locker) {number;}}});Thread thread2 new Thread(() - {for (int i 0; i 1000; i) {synchronized (locker) {number;}}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(number);} }代码解析 静态变量 number 用于存储共享计数。使用 Object locker 作为同步锁确保对 number 的修改是线程安全的。创建两个线程每个线程循环 1000 次通过 synchronized (locker) 代码块安全地增加 number。启动两个线程并等待它们结束最后输出 number 的值。 通过上述的案例我相信读者就可以对synchronized关键字有一定的理解了 当然synchronized关键字还可以修饰方法当修饰普通方法时锁对象为当前对象this修饰静态方法时锁对象为类对象class例如 public class SynchronizedMethodDemo {private static int count 0;// 修饰普通方法锁对象为thispublic synchronized void increment() {count;}// 修饰静态方法锁对象为类对象public synchronized static void staticIncrement() {count;} } 需要特别注意的是使用 synchronized 关键字会带来一定的性能开销因为获取和释放锁的过程需要消耗时间。因此在实际应用中应尽可能缩小同步代码块的范围仅在必要之处进行同步操作以此提高程序的性能。 补充synchronized关键字的可重入性 这里我们先给出可重入性的简介 可重入性是指当一个线程已经获得了某个对象的锁后它可以再次获得这个锁而不会被阻塞 例如当一个线程调用一个 synchronized 方法时若该方法内部又调用了另一个 synchronized 方法此时该线程能够继续获取锁并执行内部的 synchronized 方法而不会被自身阻塞。这是因为在可重入锁的内部机制中包含了“线程持有者”和“计数器”两个重要信息当某个线程加锁时若发现锁已被自己占用那么它仍然可以顺利获取锁并使计数器自增。只有当计数器递减为0时锁才会真正被释放从而允许其他线程获取该锁。 可重入性的特点 锁的重复获取同一个线程可以多次获取同一个锁而不会导致死锁。例如如果线程 A 已经获得了对象 O 的锁那么它可以再次进入 O 的同步方法或同步块。 计数机制Java 的 synchronized 内部使用了一个计数机制。当一个线程获得锁时计数器加一当线程释放锁时计数器减一。当计数器为零时锁被释放。  如果读者看了上述的文字解释之后还是不太理解那么我们接下看使用一个例子来帮助你进一步理解synchronized的可重入性 public class ReentrantExample {synchronized void methodA() {System.out.println(Method A is called);methodB(); // 可以在这里调用同一个对象的另一个同步方法}synchronized void methodB() {System.out.println(Method B is called);}public static void main(String[] args) {ReentrantExample example new ReentrantExample();example.methodA(); // 调用 methodA} }在上面的例子中当 methodA 被调用时线程获得了锁并执行 methodA然后可以安全地调用 methodB因为它已经持有了该对象的锁这就是synchronized的可重入性。 2volatile关键字 在了解完了synchronized关键字之后让我们了解一下volatile关键字首先先让我们了解一下什么是volatile关键字 volatile 关键字的核心作用是保证内存可见性。它强制线程在读写共享变量时必须直接从主内存读取或写入而不能使用工作内存中的副本。当一个线程修改了 volatile 修饰的变量时它会立即将修改后的值刷新到主内存并且其他线程在读取这个变量时会直接从主内存获取最新的值而不是使用自己工作内存中的旧副本 这里我们使用一个例子来进行讲解 public class VolatileDemo {private volatile boolean flag false;public void setFlag(boolean flag) {this.flag flag;}public boolean isFlag() {return flag;} } 在上述代码中flag 变量被 volatile 修饰。当一个线程调用 setFlag 方法修改 flag 的值时其他线程能够立即察觉到这个修改。 public class VolatileExample {public static void main(String[] args) {VolatileDemo volatileDemo new VolatileDemo();Thread t1 new Thread(() - {while (!volatileDemo.isFlag()) {// 线程t1在此处循环等待直到flag的值变为true}System.out.println(t1线程检测到flag为true结束循环);});Thread t2 new Thread(() - {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}volatileDemo.setFlag(true);System.out.println(t2线程将flag设置为true);});t1.start();t2.start();} } 在这个例子中t1 线程在一个循环中不断检查 volatileDemo.flag 的值如果为 false则继续循环等待t2 线程在睡眠1秒后将 flag 设置为 true。由于 flag 被 volatile 修饰当 t2 线程修改 flag 的值后t1 线程能够立即看到这个修改从而结束循环。 这样我们就了解了volatile关键字了。 以上就是本篇文章的全部内容了~~~ 文章转载自: http://www.morning.ljpqy.cn.gov.cn.ljpqy.cn http://www.morning.bfsqz.cn.gov.cn.bfsqz.cn http://www.morning.tqsmg.cn.gov.cn.tqsmg.cn http://www.morning.ygrkg.cn.gov.cn.ygrkg.cn http://www.morning.plqhb.cn.gov.cn.plqhb.cn http://www.morning.mcgsq.cn.gov.cn.mcgsq.cn http://www.morning.hwhnx.cn.gov.cn.hwhnx.cn http://www.morning.czrcf.cn.gov.cn.czrcf.cn http://www.morning.xbnkm.cn.gov.cn.xbnkm.cn http://www.morning.uytae.cn.gov.cn.uytae.cn http://www.morning.jxtbr.cn.gov.cn.jxtbr.cn http://www.morning.fglth.cn.gov.cn.fglth.cn http://www.morning.gwxsk.cn.gov.cn.gwxsk.cn http://www.morning.qkskm.cn.gov.cn.qkskm.cn http://www.morning.pmlgr.cn.gov.cn.pmlgr.cn http://www.morning.qggm.cn.gov.cn.qggm.cn http://www.morning.lrmts.cn.gov.cn.lrmts.cn http://www.morning.ddfp.cn.gov.cn.ddfp.cn http://www.morning.wfhnz.cn.gov.cn.wfhnz.cn http://www.morning.swyr.cn.gov.cn.swyr.cn http://www.morning.ltpph.cn.gov.cn.ltpph.cn http://www.morning.nqyzg.cn.gov.cn.nqyzg.cn http://www.morning.ypnxq.cn.gov.cn.ypnxq.cn http://www.morning.rxkl.cn.gov.cn.rxkl.cn http://www.morning.xnpj.cn.gov.cn.xnpj.cn http://www.morning.hbqfh.cn.gov.cn.hbqfh.cn http://www.morning.lmjkn.cn.gov.cn.lmjkn.cn http://www.morning.knmp.cn.gov.cn.knmp.cn http://www.morning.hwtb.cn.gov.cn.hwtb.cn http://www.morning.mplb.cn.gov.cn.mplb.cn http://www.morning.pylpd.cn.gov.cn.pylpd.cn http://www.morning.wbrf.cn.gov.cn.wbrf.cn http://www.morning.pjtnk.cn.gov.cn.pjtnk.cn http://www.morning.hxpff.cn.gov.cn.hxpff.cn http://www.morning.yszrk.cn.gov.cn.yszrk.cn http://www.morning.nhdmh.cn.gov.cn.nhdmh.cn http://www.morning.rqgq.cn.gov.cn.rqgq.cn http://www.morning.bkryb.cn.gov.cn.bkryb.cn http://www.morning.pfkrw.cn.gov.cn.pfkrw.cn http://www.morning.khdw.cn.gov.cn.khdw.cn http://www.morning.ptqpd.cn.gov.cn.ptqpd.cn http://www.morning.hypng.cn.gov.cn.hypng.cn http://www.morning.chfxz.cn.gov.cn.chfxz.cn http://www.morning.hhmfp.cn.gov.cn.hhmfp.cn http://www.morning.jfbbq.cn.gov.cn.jfbbq.cn http://www.morning.gcthj.cn.gov.cn.gcthj.cn http://www.morning.zxgzp.cn.gov.cn.zxgzp.cn http://www.morning.fqyxb.cn.gov.cn.fqyxb.cn http://www.morning.nbqwr.cn.gov.cn.nbqwr.cn http://www.morning.jzykw.cn.gov.cn.jzykw.cn http://www.morning.zdqsc.cn.gov.cn.zdqsc.cn http://www.morning.clpkp.cn.gov.cn.clpkp.cn http://www.morning.mldrd.cn.gov.cn.mldrd.cn http://www.morning.ybnzn.cn.gov.cn.ybnzn.cn http://www.morning.lqznq.cn.gov.cn.lqznq.cn http://www.morning.gqjwz.cn.gov.cn.gqjwz.cn http://www.morning.zckhn.cn.gov.cn.zckhn.cn http://www.morning.dyxlm.cn.gov.cn.dyxlm.cn http://www.morning.mcjrf.cn.gov.cn.mcjrf.cn http://www.morning.mbhdl.cn.gov.cn.mbhdl.cn http://www.morning.zbqry.cn.gov.cn.zbqry.cn http://www.morning.knqzd.cn.gov.cn.knqzd.cn http://www.morning.jpgfq.cn.gov.cn.jpgfq.cn http://www.morning.phzrq.cn.gov.cn.phzrq.cn http://www.morning.wjfzp.cn.gov.cn.wjfzp.cn http://www.morning.qjlkp.cn.gov.cn.qjlkp.cn http://www.morning.nkjjp.cn.gov.cn.nkjjp.cn http://www.morning.zsfooo.com.gov.cn.zsfooo.com http://www.morning.tnktt.cn.gov.cn.tnktt.cn http://www.morning.sffwz.cn.gov.cn.sffwz.cn http://www.morning.nwgkk.cn.gov.cn.nwgkk.cn http://www.morning.rntyn.cn.gov.cn.rntyn.cn http://www.morning.chhhq.cn.gov.cn.chhhq.cn http://www.morning.rbmm.cn.gov.cn.rbmm.cn http://www.morning.kgnnc.cn.gov.cn.kgnnc.cn http://www.morning.pgzgy.cn.gov.cn.pgzgy.cn http://www.morning.ghxkm.cn.gov.cn.ghxkm.cn http://www.morning.dsgdt.cn.gov.cn.dsgdt.cn http://www.morning.nyqm.cn.gov.cn.nyqm.cn http://www.morning.hhqtq.cn.gov.cn.hhqtq.cn 查看全文 http://www.tj-hxxt.cn/news/277434.html 相关文章: 网站制作 深圳信科网络济南软件网站建设 网站建设需要服务器网站建设公司官方网站 网站下雪代码wordpress一页主题 ovz的vps怎么做网站网站上的缩略图怎么做清晰 电商设计网站有哪些网站系统升级维护需要多长时间 做网站的流程视频响应式网站如何做的 网站建设与管理课程标准网站备案信息找回 北湖区网站建设怎么快速建网站教程 网站建设流程及规范美橙网站建设南的 成都高端品牌网站建设电子商务网站的建设及规划 美容院门户网站开发荆门建设局官方网站 网站备案后名称怎么改上海公共招聘官网 网站开发询价表模板下载当雄网站建设 企业网站快速建站网站开发语言比较 做网站一定要虚拟主机吗网站顶部伸缩广告 家电网站建设费用手机怎么制作网页 学校网站改版电子政务和网站建设工作的总结 做饲料推广哪个网站好怎么给自己的品牌做网站 深圳网站网络推广公司wordpress 软件主题 浙江省两学一做网站论坛网站怎么做 响应试企业网站惠州技术支持网站建设 做app网站的软件有哪些软件开发培训视频 有孩子做的网站搜索优化报价 网站怎么绑定域名网站主机 分为 设计网站用什么语言建一个c2c网站要多少钱 网站建设注意那阿克苏建设网站 图书类网站开发的背景discuz做电影网站 网站404页面优化网站开发 工具 官方网站建设计划百度 网站 说明 企业网站建设之域名篇国外网络推广服务