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

vs2012网站开发课程设计百度竞价代运营外包

vs2012网站开发课程设计,百度竞价代运营外包,东莞有互联网企业吗,中国产业信息网目录 前言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/466227.html

相关文章:

  • 建设网站培训学校精准推广
  • 表单大师做网站百度seo优化怎么做
  • 农业畜牧网站开发深圳网络推广案例
  • 手机做wifi中继上外国网站股票指数是什么意思
  • 网站系统开发报价单网站自助建站系统
  • 如何做电影网站推广怎样制作网页设计
  • 有没有专门做ppt的网站品牌策划案
  • 做网站 单页数量怎么做属于自己的网站
  • 地方网站改版方案个人网站模板建站
  • 哪些经营范围可以开网站建设费用十大免费网站推广平台有哪些
  • wordpress 百度bae网站排名怎么优化
  • 那个网站做教学视频广州网络seo优化
  • 做淘宝客网站需要什么要求吗厦门网站优化公司
  • 成都手机网站建设哪百度关键词seo排名软件
  • 免费网站制作知乎新网站百度seo如何做
  • 网站开发软件费用免费网站排名优化软件
  • 重庆做营销型网站建设公司百度是国企还是央企
  • wordpress文章如何匪类长沙网站优化公司
  • 有没有什么专业做美业的网站软文范文大全1000字
  • 政府网站集约化建设进展汇报广州公司关键词网络推广
  • 哪里有网站建设的企业网站建设加推广优化
  • 给别人做网站多少钱新产品推广方案策划
  • 网站的策划与建设阶段百度关键词挖掘工具爱站网
  • 做旅游海报的软件或是网站关键词查询网
  • 广西建网站公司湘潭关键词优化服务
  • 国外做外贸哪个网站好些搜狗搜索网页版
  • 惠州最专业的网站建设公司seo网站优化方法
  • 空间站建设百度关键词热度查询工具
  • 南充做网站公司哪家好电子商务沙盘seo关键词
  • 网站目录做跳转营销型网站分为哪几种