并发编程(三)原子性(1)
创始人
2024-02-07 22:35:31
0

【认识原子性】:

一个小程序认识原子性:

package T05_YuanZiXing;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class T00_00_IPlusPlus {private static long n = 0L;public static void main(String[] args) throws Exception {//Lock lock = new ReentrantLock();Thread[] threads = new Thread[100];CountDownLatch latch = new CountDownLatch(threads.length);for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < 10000; j++) {n++;}latch.countDown();});}for (Thread t : threads) {t.start();}latch.await();System.out.println(n);}
}

【最终输出】:
在这里插入图片描述
//启动了100个线程 , 每个线程将数字加到1W , 最后应该是100W。
【问题所在】:

在这里插入图片描述
多个线程同时拿到了变量,同时++,然后同时写回去。

【一些概念】:
race condition => 竞争条件 , 指的是多个线程访问共享数据的时候产生竞争———上述程序中变量n即是共享数据。

数据的不一致(unconsistency),并发访问之下产生的不期望出现的结果

如何保障数据一致呢?–> 线程同步(线程执行的顺序安排好),

monitor (管程) —> 锁

critical section -> 临界区

如果临界区执行时间长,语句多,叫做 锁的粒度比较粗,反之,就是锁的粒度比较细。

【修改程序】:

        for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < 10000; j++) {synchronized (T00_01_IPlusPlus.class) {//lock.lock();n++;//lock.unlock();}}latch.countDown();});}

【原子操作】:

原子操作的意思就是不能够中间被打断 , 只能作为一个整体 , 不能并发执行 。

【什么样的语句是原子性的,什么样的语句不是原子性的呢?】:

不管是Java、C、C++、高级语言、低级语言 最终一定都是要搞成机器语言的。机器语言翻译过来就是汇编语言。即便是汇编语言,它执行的任何一条指令都有可能被其他的线程所打断。
【得查汇编手册】:

CPU级别汇编,需要查询汇编手册!

Java中的8大原子操作:(了解即可,无需背过)

  1. lock:主内存,标识变量为线程独占
  2. unlock:主内存,解锁线程独占变量
  3. read:主内存,读取内存到线程缓存(工作内存)
  4. load:工作内存,read后的值放入线程本地变量副本
  5. use:工作内存,传值给执行引擎
  6. assign:工作内存,执行引擎结果赋值给线程本地变量
  7. store:工作内存,存值到主内存给write备用
  8. write:主内存,写变量值

【为何不用背呢?】:

//正常的情况下 , 你判断不了的情况下。这句话到底是否具备原子性呢?——你给它上锁就可以了。

【n++翻译成汇编指令】:

在这里插入图片描述
在这里插入图片描述
1——将static的值给拿过来;
2——扔到栈空间里面;
3——将这个值++;
4——将值放回去;
5——返回。

【 用上锁保证原子性 】:

synchronized (T00_01_IPlusPlus.class) {n++;
}

//大括号里面的所有操作都被当作了一个整体——不可打断。

【上锁的本质(一)】:

一句高级语言翻译成机器语言可能有好多句。需要保证这些操作不被打断。

【上锁的本质(二)】:

上锁的本质就是把并发编程序列化。
【程序解释】:

package T05_YuanZiXing;import Utils.SleepHelper;public class T00_01_WhatIsLock {private static Object o = new Object();public static void main(String[] args) {Runnable r = () -> {System.out.println(Thread.currentThread().getName() + " start!");SleepHelper.sleepSeconds(2);System.out.println(Thread.currentThread().getName() + " end!");};for (int i = 0; i < 3; i++) {new Thread(r).start();}}
}

【最终输出】:
在这里插入图片描述
//基本上是同时启动 , 2秒之后同时结束。

【进行改进】:

package T05_YuanZiXing;import Utils.SleepHelper;public class T00_01_WhatIsLock_02 {private static Object o = new Object();public static void main(String[] args) {Runnable r = () -> {synchronized (o) {System.out.println(Thread.currentThread().getName() + " start!");SleepHelper.sleepSeconds(2);System.out.println(Thread.currentThread().getName() + " end!");}};for (int i = 0; i < 3; i++) {new Thread(r).start();}}
}

【最终输出】:
在这里插入图片描述
//红线处会等待2S , 一共执行完需要6S的时间。

【理解序列化】:


原先上厕所,三个人同时一起完成,现在要排队一个一个完成了。

【上锁的本质(三)】:

【程序演示】:

package T05_YuanZiXing;import Utils.SleepHelper;public class T00_02_SingleLockVSMultiLock {private static Object o1 = new Object();private static Object o2 = new Object();private static Object o3 = new Object();public static void main(String[] args) {Runnable r1 = () -> {synchronized (o1) {System.out.println(Thread.currentThread().getName() + " start!");SleepHelper.sleepSeconds(2);System.out.println(Thread.currentThread().getName() + " end!");}};Runnable r2 = () -> {synchronized (o2) {System.out.println(Thread.currentThread().getName() + " start!");SleepHelper.sleepSeconds(2);System.out.println(Thread.currentThread().getName() + " end!");}};Runnable r3 = () -> {synchronized (o3) {System.out.println(Thread.currentThread().getName() + " start!");SleepHelper.sleepSeconds(2);System.out.println(Thread.currentThread().getName() + " end!");}};new Thread(r1).start();new Thread(r2).start();new Thread(r3).start();}
}

【最终输出】:
//一共花了2秒。

【上锁的本质(四)】:

synchronized是可以保障可见性的,一个线程结束了,会向主内存中做同步;
synchronized保障了原子性。
但是synchronized无法保障有序性。

sync操作中的绿色区域部分的执行顺序是完全可以发生变化的。

【有序性】:

单线程保障最终一致性 , 它和锁没有关系。

【 一些同步的基本概念_锁的粒度 】:

【 monitor(管程) 】:

在这里插入图片描述
//后面跟的那一部分叫做monitor。
在这里插入图片描述
// o 即 monitor。

【 critical section( 临界区 )】:

当我持有这把锁的时候,我所执行的代码 , 它是临界区 , 是不能够两个同时在一起的,是必须顺序的,按照序列化执行的。
【实际例子解释临界区】:

在这里插入图片描述
sync大括号所包含的叫做临界区——(图中的红色区域)。
如果临界区执行的时间比较长,语句比较多 , 那我们就说锁的粒度比较粗 , 反之,就是锁的粒度比较细。

【阶段小结】:

【如何保障临界区操作的原子性呢?】:

1)乐观锁
2)悲观锁

相关内容

热门资讯

细节决定成败的名言 关于细节决定成败的名言  在日常生活或是工作学习中,大家都经常接触到名言吧,在议论文中,引用名言,不...
表示母爱的格言 表示母爱的格言  慈母爱子,非为报也,表示母爱的格言。以下是关于表示母爱的格言,希望对大家有帮助! ...
大卫·休谟的名言   大卫·休谟(David Hume,1711年4月26日-1776年8月25日下午4点钟)是英格兰...
成功格言:书山有路勤为径,学... 成功格言:书山有路勤为径,学海无涯苦作舟  1、发奋忘食(废寝忘食)  ——《论语·述而》  【记】...
安全教育名言   安全教育名言  1、查隐患及时整改不马虎,纠违章严肃处理不放过。  2、穿马路是左右看,用家电是...
保尔的名言 保尔的名言  1、一个人的生命应当这样度过:当他回首往事的时候不会因虚度年华而悔恨,也不会因碌碌无为...
诚信的名言 有关诚信的名言15篇  在日常的学习、工作、生活中,大家最不陌生的就是名言了吧,名言主要用来激励和告...
环保的名言名句 环保的名言名句  在平平淡淡的日常中,大家总免不了要接触或使用名言吧,在议论文中,引用名言,不但体现...
自强不息的名言名句 自强不息的名言名句  自强不息的名言名句【经典篇】  1、生活的目标,是唯一值得寻找的财富。——史蒂...
教师人生格言大全   教师人生格言大全    1、 教师如果对学生没有热情,决不能成为好教师。但是教师对于学生的爱是一...
简短的人生格言 简短的人生格言集锦55句  人假使没有自尊心,那就会一无价值。——[俄国]屠格涅夫以下是小编为大家推...
谦虚的名言 谦虚的名言  谦虚的名言  在日常学习、工作或生活中,说到名言,大家肯定都不陌生吧,名言可以带来警醒...
珍爱生命的名人名言 珍爱生命的名人名言(精选55句)  关于生命的名人名言有哪些?生命,值得我们尊重,你知道哪些关于生命...
关于知音的名言名句  导语:关于知音或者是友谊的古诗词, 名人名言,这里全都有,关于知音的名言名句。  君子之交淡若水,...
清正廉洁格言 清正廉洁格言最短的人生格言1、执政以廉为本,为官以勤为先。2、做人一身正气,为官一尘不染。3、名位利...
罗素名言 罗素名言69句  1、伟大的事业是根源于坚韧不断的工作,以全付精神去从事,不避艰苦。——罗素  2、...
朋友的名人名言 有关朋友的名人名言汇总  在学习、工作、生活中,大家都不可避免地会接触并使用名言吧,名言可以用来鞭策...
乔布斯名言经典摘抄 乔布斯名言经典摘抄  乔布斯出生于美国加利福尼亚州旧金山,美国发明家、企业家、美国苹果公司联合创办人...
夺眶而出的名言名句 关于夺眶而出的名言名句  这里是郁郁葱葱的山神之森,一定,要有一段时间无法再盼望夏天了,心如刀绞,泪...
信仰名言 精选关于信仰名言  关于信仰名言  1、没有信仰的人如同盲人(弥顿)  2、有信仰未必能成大事,而没...