当前位置: 首页 > wzjs >正文

少儿图书销售网站开发背景网络营销的缺点及建议

少儿图书销售网站开发背景,网络营销的缺点及建议,南通做电力的公司网站,牛天下网站做的怎么样目录 前言1.线程安全的定义2.线程安全问题产生的原因2.1 多个线程修改一个变量2.2 修改操作不是原子的2.3 内存可见性引起的线程安全问题 3.解决线程安全问题的方法3.1 通过synchronized关键字加锁3.2 使用volatile关键字 总结 前言 在使用多线程的时候,难免会出现…

目录

  • 前言
  • 1.线程安全的定义
  • 2.线程安全问题产生的原因
    • 2.1 多个线程修改一个变量
    • 2.2 修改操作不是原子的
    • 2.3 内存可见性引起的线程安全问题
  • 3.解决线程安全问题的方法
    • 3.1 通过synchronized关键字加锁
    • 3.2 使用volatile关键字
  • 总结

前言

在使用多线程的时候,难免会出现一些问题,会产生线程安全问题,本篇文章就来简单讲述一下线程安全问题产生的原因和对应的解决方案。

1.线程安全的定义

线程安全是指当多个线程同时访问某个对象或方法时,不会出现数据不一致、逻辑错误或者意外结果的情况。即当把一个单线程执行的程序修改成一个多线程程序,产生的结果要和原来一样,如果不一样,则可以认为出现了线程安全问题。

2.线程安全问题产生的原因

造成线程不安全有各种各样的原因,但是导致线程不安全的根本原因就是线程的调度是随机的。下面还有一些常见的原因。

2.1 多个线程修改一个变量

多个线程同时访问共享资源(比如说同一个变量)可能会产生竞争状态,比如一个线程读取的是1,然后改成2,还没有保存,另一个线程也来读取,此时读取的还是1,这就会导致每次多线程执行完毕的时候,得出的结果可能都不一样。

2.2 修改操作不是原子的

就比如说对变量进行++操作,在java语句中是一行代码,实际上是三个操作:读取内存数据到CPU;对数据进行更新;然后将数据写回CPU。
在进行多线程操作的时候,可能就会因为操作顺序的抢占而产生线程安全问题

2.3 内存可见性引起的线程安全问题

下面先给出一段代码:

public class Demo17 {private static int flag = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while(flag == 0){//do nothing}System.out.println("t1线程结束");});Thread t2 = new Thread(() -> {Scanner scanner = new Scanner(System.in);System.out.println("请输入一个数字:");flag = scanner.nextInt();System.out.println("t2线程结束");});t1.start();t2.start();t1.join();t2.join();}
}

我们来尝试运行一下
我们输入一个非零数字,理论上应该弹出t1线程结束和t2线程结束,我们来看结果:
在这里插入图片描述
我们发现并没有显示预期的结果,这是为什么?
这里就是由于”内存可见性“。
意思就是这里t2对flag进行修改,但是t1没有感知到,就是t1”没有看见“,一直认为flag还是0。
这就是内存可见性问题。
这是由于编译器优化所产生的问题,在代码编译时,编译器会进行一些优化策略,对代码进行优化,来提高程序的效率,这里是由于编译器优化出现了误判,从而导致代码的逻辑发生了改变,上面的程序就是由于此原因而出现问题,在t1的反复循环中,flag会被存进寄存器里来提高读取效率,不通过内存来读,而t2把通过内存把flag的数值变化后,t1仍然读的是原来存取到寄存器中的‘0’的值,这就是t1线程“看不见”flag的值变化的原因。

3.解决线程安全问题的方法

上述的根本原因不好解决,我们可以通过把修改操作变成”原子的“ 来解决线程安全问题

3.1 通过synchronized关键字加锁

可以通过加锁的方式将多段代码变成一个整体,让其它的线程无法进行干扰。我们通过synchronized关键字来实现锁。
比如我们对如下代码进行分析:

public class Demo14 {public static int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count++;}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count++;}});t1.start();t2.start();t1.join();t2.join();System.out.println("count = " + count);}
}

可以看出这里的操作并不是原子的,所以并不能如愿获得100000的结果。
我们就需要使用synchronized关键字来进行加锁,方法如下:

package thread;/*** @author Wind* @date 2025-04-13*/
public class Demo14 {public static int count = 0;private static Object locker = new Object();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {synchronized (locker) {count++;}}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {synchronized (locker){count++;}}});t1.start();t2.start();t1.join();t2.join();System.out.println("count = " + count);}
}

将count++操作进行加锁,在执行count++前,后台会将语句lock,在调用完count++操作后,进行unlock操作,假设当t1加锁后,t2要进行count++前,要执行加锁,此时加锁不成功,会阻塞等待,知道t1进行unlock,这样就不会导致多个线程对同一个变量进行修改。现在观看结果,可以发现结果正确:
在这里插入图片描述
synchronized还可以用来修饰方法,同时也能起到加锁的作用:

public class Demo14 {static class Counter{private int count = 0;private Object locker = new Object();synchronized public void add() {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("count = " + counter.count);}
}

这里实际上就是对add方法加锁。

synchronized也可以对静态方法加锁,此时可以认为是对类对象进行加锁。

3.2 使用volatile关键字

使用volatile关键字可以解决上面所出现的内存可见性问题。
volatile关键字用于修饰变量,用于告诉编译器,这个变量是经常性变化的,使编译器不对变量进行上面内存可见性中所出现的优化。
修改后的代码(将flag用volatile修饰):

public class Demo17 {private static volatile int flag = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while(flag == 0){//do nothing}System.out.println("t1线程结束");});Thread t2 = new Thread(() -> {Scanner scanner = new Scanner(System.in);System.out.println("请输入一个数字:");flag = scanner.nextInt();System.out.println("t2线程结束");});t1.start();t2.start();t1.join();t2.join();}
}

下面看运行结果:
在这里插入图片描述
可以看到,程序正常结束。
此外还需要注意的是,volatile虽然可以解决内存可见性问题,但它本身不具有原子性,无法解决不是原子性的问题。

总结

以上就是对线程安全的简单介绍,希望这篇文章能帮助你更加熟练的运用多线程。

http://www.dtcms.com/wzjs/313982.html

相关文章:

  • 怎样会展网站建设合肥网站制作公司
  • 美人主意的暴利行业长沙竞价优化
  • 网站做锚点好搜网
  • 在线网站设计新手怎样推销自己的产品
  • 如何做自己的小说网站网页模板免费下载网站
  • sqlite 做网站网络营销计划包括哪七个步骤
  • 提供网站推广公司电话推广普通话手抄报简单又好看内容
  • 赤峰网站开发公司seo自学网站
  • 泰安微信网站制作长沙seo管理
  • wordpress怎么制作网站主页西点培训
  • 网站的制作哪家好体验营销理论
  • 一般什么企业需要建站营销咨询公司
  • seo关键词排名优化制作泽成杭州seo网站推广排名
  • 网站域名不合法成人教育培训机构十大排名
  • 字体logo设计在线生成器西安seo包年服务
  • 百度公司有哪些部门武汉seo网站排名优化
  • 百度搜索风云榜网络优化的基本方法
  • 网站开发好什么进行界面的优化今日舆情热点
  • 做网站预算网络推广app是违法的吗
  • 邯郸教育平台网站建设电子商务营销方法
  • 网站建设规划表今日头条官网首页
  • wordpress更改主站点软文广告示范
  • 天津免费建设网站台州seo排名扣费
  • 网页编辑和发布流程不包括以下哪个选项网站优化推广服务
  • 眼镜企业网站建设方案竞价托管一般多少钱
  • 网站开发 流程百度笔记排名优化
  • 布吉做网站公司简述什么是seo
  • 重庆网站建设找珊瑚云上海优化营商环境
  • 四川省建设工程造价信息网站google seo 优化招聘
  • 数据库性质的网站怎么做网络推广的方法