Java多线程详解(原子性、有序性、可见性),夯实基础就在今天

为什么需要并发,多线程?

  1. 时代的召唤,为了更充分的利用多核CPU的计算能力,多个线程程序可通过提高处理器的资源利用率来提升程序性能。

  2. 方便业务拆分,异步处理业务,提高应用性能。

多线程并发产生的问题?

  1. 大量的线程让CPU频繁上下文切换带来的系统开销。

  2. 临界资源线程安全问题(共享,可变)。

  3. 容易造成死锁。

注意:当多个线程执行一个方法时,该方法内部的局部变量并不是临界资源,因为这些局部变量是在每个线程的私有栈中,因此不具有共享性质,不会导致线程安全问题。

可见性

多线程访问同一个变量时,如果有一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。这是因为为了保证多个CPU之间的高速缓存是一致的,操作系统会有一个缓存一致性协议,volatile就是通过OS的缓存一致性协议策略来保证了共享变量在多个线程之间的可见性。

public class ThreadDemo2 {

private static boolean flag = false;

public void thread_1(){

flag = true;

System.out.println(“线程1已对flag做出改变”);

}

public void thread_2(){

while (!flag){

}

System.out.println(“线程2->flag已被修改,成功打断循环”);

}

public static void main(String[] args) {

ThreadDemo2 threadDemo2 = new ThreadDemo2();

Thread thread2 = new Thread(()->{

threadDemo2.thread_2();

});

Thread thread1= new Thread(()->{

threadDemo2.thread_1();

});

thread2.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

thread1.start();

}

}

执行结果

线程1已对flag做出改变

代码无论执行多少次,线程2的输出语句都不会被打印。为flag添加volatile修饰后执行,线程2执行的语句被打印

执行结果

线程1已对flag做出改变

线程2->flag已被修改,成功打断循环

局限:volatile只是保证共享变量的可见性,无法保证其原子性。多个线程并发时,执行共享变量i的i++操作<==> i = i + 1,这是分两步执行,并不是一个原子性操作。根据缓存一致性协议,多个线程读取i并对i进行改变时,其中一个线程抢先独占i进行修改,会通知其他CPU我已经对i进行修改,把你们高速缓存的值设为无效并重新读取,在并发情况下是可能出现数据丢失的情况的。

public class ThreadDemo3 {

private volatile static int count = 0;

public static void main(String[] args) {

for (int i = 0; i < 10; ++i){

Thread thread = new Thread(()->{

for (int j = 0; j < 1000; ++j){

count++;

}

});

thread.start();

}

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“count执行的结果为->” + count);

}

}

执行结果

count执行的结果为->9561

注意:这个结果是不固定的,有时10000,有时少于10000。

原子性

就像恋人一样同生共死,表现在多线程代码中程序一旦开始执行,就不会被其他线程干扰要嘛一起成功,要嘛一起失败,一个操作不可被中断。在上文的例子中,为什么执行结果不一定等于10000,就是因为在count++是多个操作,1.读取count值,2.对count进行加1操作,3.计算的结果再赋值给count。这几个操作无法构成原子操作的,在一个线程读取完count值时,另一个线程也读取他并给它赋值,根据缓存一致性协议通知其他线程把本次读取的值置为无效,所以本次循环操作是无效的,我们看到的值不一定等于10000,如何进行更正---->synchronized关键字

public class ThreadDemo3 {

private volatile static int count = 0;

private static Object object = new Object();

public static void main(String[] args) {

for (int i = 0; i < 10; ++i){

Thread thread = new Thread(()->{

for (int j = 0; j < 1000; ++j){

synchronized (object){

count++;

}

}

});

thread.start();

}

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“count执行的结果为->” + count);

}

}

执行结果

count执行的结果为->10000

加锁后,线程在争夺执行权就必须获取到锁,当前线程就不会被其他线程所干扰,保证了count++的原子性,至于synchronized为什么能保证原子性,篇幅有限,下一篇在介绍。

有序性

jmm内存模型允许编译器和CPU在单线程执行结果不变的情况下,会对代码进行指令重排(遵守规则的前提下)。但在多线程的情况下却会影响到并发执行的正确性。

public class ThreadDemo4 {

private static int x = 0,y = 0;

private static int a = 0,b = 0;

private static int i = 0;

public static void main(String[] args) throws InterruptedException {

for (;😉{

i++;

x = 0;y = 0;

a = 0;b = 0;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

很多程序员,整天沉浸在业务代码的 CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。

我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。

不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。

我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。

不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值