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

批量发布文章到wordpressseo教学培训

批量发布文章到wordpress,seo教学培训,做按摩网站有生意吗,品牌做网站还是app引言: 如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的 线程安全问题的原因: 一.操作系统的随机调度 : 二.多个线程修改同一个变量: 三.修改操作不是…

引言: 

如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的


线程安全问题的原因:

一.操作系统的随机调度 :

二.多个线程修改同一个变量: 

三.修改操作不是原子的 :

四.内存可见性 :

五.指令重排序:  

解决上述的线程安全问题的措施:   



线程安全问题的原因:

 一.操作系统的随机调度 :  

1. 这是线程安全问题的 罪魁祸首 随机调度使⼀个程序在多线程环境下, 执行顺序存在很多的变数.

例子:这个代码返回结果就是随机调度的体现 

 现象: 

class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("这⾥是t线程运⾏的代码");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class Demo1 {public static void main(String[] args) throws InterruptedException {MyThread t = new MyThread();t.start();while (true) {System.out.println("这里是主线程");Thread.sleep(1000);}}
}

现象: 


二.多个线程修改同一个变量: 

上⾯的线程不安全的代码中, 涉及到多个线程针对 count 变量进行修改.
此时这个 count 是⼀个多个线程都能访问到的 "共享数据" 
 

例子:下面这个代码应该预期应该自增10w次,但是由于线程安全问题,达不到预期 
public class Demo11 {private static int count = 0;public static void main(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();// 一个线程自增 5w 次, 两个线程, 总共自增 10w 次. 预期结果, count = 10wSystem.out.println(count);}
}

三.修改操作不是原子的 : 

这里我们count++,时候站在操作系统层面,我们要进行大致三步:

load:把count的值读到寄存器里 

add: 把寄存器中的内容加1

save:  把寄存器写回内存  

进行以上以上操作时候由于操作系统随机调度多个线程之间,可能出现数据被覆盖的情况,这就是操作不原子的体现: 


四.内存可见性 : 

这个问题可以引入Java内存模型说明: 

线程之间的共享变量存在 主内存 (Main Memory).(主内存就是泛指的内存)
每⼀个线程都有自己的 "工作内存" (Working Memory) .(工作内存指的是CPU 的寄存器和高速缓存L1,L2,L3)
当线程要读取一个共享变量的时候, 会先把变量从主内存拷贝到工作内存(CPU 的寄存器), 再从工作内存(CPU 的寄存器),读取数据。 
其实是通过jvm和编译器来实现优化,把读内存优化为读寄存器了,有时候这个优化逻辑不符合我们的预期的逻辑出现细节上的偏差,就导致内存可见性问题

代码实例:一个线程读取一个线程修改
这个循环条件的flag判断是条件跳转指令cmp是寄存器操作会很快,while会循环很多次,jvm觉得每次觉得读到的都是0,直接就把 读内存优化为读寄存器了, 此时寄存器的值为0,此时用户输入 1 想结束线程时,t1线程读不到这个在内存中(主内存)的值,所以这个t1线程结束不了
public static void main(String[] args) {Thread t1 = new Thread(()->{while (flag == 0){}System.out.println("t1线程结束");});Thread t2 = new Thread(()->{Scanner in = new Scanner(System.in);System.out.println("请输入flag的值");flag = in.nextInt();});t1.start();t2.start();}


五.指令重排序:

要说清楚这个问题就要引入一种设计模式:单例模式

 单例模式: 

单例模式能保证某个类在程序中只存在唯⼀⼀份实例, 而不会创建出多个实例,不能创建多个对象,这里有两种写法:饿汉模式和懒汉模式: 

1.饿汉模式:  类加载的同时, 创建实例:  
类加载时就new对象所以成为饿汉模式,注意构造方法私有化,防止类外多次实例化。
​
class Singleton {private static Singleton instance = new Singleton();//类加载时就new对象//构造方法私有化,防止类外被实例化多个对象private Singleton() {}public static Singleton getInstance() {return instance;}
}​

2.懒汉模式-单线程版:  

懒汉模式,能不实例化就不实例化所以的懒汉, 第⼀次使用的时候才创建实例

class Singleton {private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

 但是这个在多线程下还是存在线程安全问题的,而且还有一个指令重排序问题 。

 就算加锁(结合下面看看),解决了线程安全问题,但是instance = new Singleton();

new对象操作,细分为这三步:

1 .申请内存空间

2.构造对象(初始化)

3.内存空间首地址,赋值给引用变量  
由于指令重排序,可能会改变顺序,顺序可能从1,2,3一一>1,3,2  
在这个代码情况下就可能,在类外调用,getInstance方法拿到未初始化的对象导致线程安全问题。
 
class Singleton {private static Singleton instance = null;private static Object locker = new Object(); private Singleton() {}public synchronized static Singleton getInstance() {if(instance == null) {//进一步优化效率,减少锁的阻塞状态,(instance == null才加锁才new对象)synchronized(locker){if (instance == null) {instance = new Singleton();}}}return instance;}}



解决上述的线程安全问题的措施:   

操作系统的随机调度 是操作系统,计算机一脉传承,不能解决,
接下来我们围绕三~四~五~展开 

三.修改操作不是原子的 : 

这里我们可以把相关的操作打包起来,就是引入锁:

synchronized 关键字 - 监视器锁 monitor lock :

synchronized 会起到互斥效果, 某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也执行 到同⼀个对象 synchronized 就会阻塞等待.
进⼊ synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁 
 就和上厕所一样:

理解 "阻塞等待":
针对每⼀把锁, 操作系统内部都维护了⼀个等待队列. 当这个锁被某个线程占有的时候, 其他线程尝试 进行加锁, 就加不上了, 就会阻塞等待, ⼀直等到之前的线程解锁之后, 由操作系统唤醒⼀个新的线程, 再来获取到这个锁。
注意:这里还有一种应用程序级别的忙等,不涉及操作系统

三.的解决代码:

这里注意两个线程要加他一把锁,才有互斥的效果。 

 

 private static int count = 0;public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread t1 = new Thread(() -> {synchronized (locker) {for (int i = 0; i < 50000; i++) {count++;}}System.out.println("t1 结束");});Thread t2 = new Thread(() -> {synchronized (locker) {for (int i = 0; i < 50000; i++) {count++;}}System.out.println("t2 结束");});t1.start();t2.start();t1.join();t2.join();// 一个线程自增 5w 次, 两个线程, 总共自增 10w 次. 预期结果, count = 10wSystem.out.println(count);}
  

四.内存可见性解决:  

这里引入volatile关键字:


1.volatile 能保证每次读取操作都是读内存

2.volatile 能保证变量的读取和修改不会出发指令重排序 

​public class{
public volitile static int flag = 0 //这样修饰变量编译器就不会优化了
public static void main(String[] args) {Thread t1 = new Thread(()->{while (flag == 0){}System.out.println("t1线程结束");});Thread t2 = new Thread(()->{Scanner in = new Scanner(System.in);System.out.println("请输入flag的值");flag = in.nextInt();});t1.start();t2.start();}​}

五.指令重排序:

饿汉模式是没有线程安全问题和指令重排序的,因为都是读操作

懒汉模式下就会有:

我们也加上volatile关键字:

​
class Singleton {private static volatile Singleton instance = null;//加上volatile private static Object locker = new Object(); private Singleton() {}public synchronized static Singleton getInstance() {if(instance == null) {//进一步优化效率,减少锁的阻塞状态,(instance == null才加锁才new对象)synchronized(locker){if (instance == null) {instance = new Singleton();}}}return instance;}}​

http://www.mnyf.cn/news/42671.html

相关文章:

  • 教人做窗帘的视频网站短视频seo排名加盟
  • seo是东莞企业网站排seo百度霸屏推广一般多少钱
  • 二次元百科官网wordpress深圳防疫措施优化
  • 企业做网站优点百度一下手机版网页
  • 手机网站合同社群营销平台有哪些
  • 做鼻翼整形整形的网站营销软文写作
  • 十大场景营销案例宁德seo推广
  • 怎么做视频解析网站吗成人职业技能培训班
  • 公司网站的服务器网络推广公司专业网络
  • 成交型网站建设价格做企业推广的公司
  • 如何自己做网站模版seo管理平台
  • 河南省做网站的公司百度地图关键词优化
  • 遵义 网站建设长沙全网覆盖的网络推广
  • visio网站建设流程图免费刷推广链接的软件
  • 网站建设用苹果系统与liunx360建站和凡科哪个好
  • 网站的电子画册怎么做百度商城app
  • 四川省建设工程质量监理协会网站怎么自己弄一个平台
  • 个人网站策划书怎么做引擎优化seo
  • 企业网站搜索引擎推广方法包括怎么做起泡胶
  • 北京亦庄做网站公司百度云网盘下载
  • 博客网站需要的功能百度移动端排名
  • 武汉市内做网站的公司苏州百度代理公司
  • 建设银行手机不用了怎么登陆网站提供seo服务
  • 江门seo网站云南seo简单整站优化
  • 高端品牌网站建设费用今晚赛事比分预测
  • 提供做网站火锅店营销方案
  • 有没有专业做二维码连接网站在认识网络营销
  • 海尔集团的电子商务网站建设自媒体平台收益排行榜
  • 滨海哪家专业做网站5g站长工具查询
  • wordpress怎么改后台聊城优化seo