前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >1.多线程-了解多线程与高并发

1.多线程-了解多线程与高并发

作者头像
杨小杰
发布2019-07-04 16:27:01
5730
发布2019-07-04 16:27:01
举报
文章被收录于专栏:JAVA知识总结与分享
并发与并行的区别:
并发:两个任务或者多个任务执行,多个任务交替执行
并行:两个任务或者多个任务一起同时执行
例子:

一个CPU,去执行一个多线程任务。是不可能并行的,一个CPU只能执行一条命令,CPU会高速的切换线程任务去执行。这种情况下线程是并发的。 一个系统中拥有多个CPU,执行多线程任务,多个CPU会同时执行任务,这种情况是并行。并行也只可能出现在多核CPU中。 两者虽然本质不同,但是造成的最终效果是一样的。没有太必要做详细的区分。

临界区:

临界区用来表示一个共享资源,可以被多个线程使用,但是每一次,只能有一个线程去使用。相等于厕所的坑。

阻塞非阻塞:

假如有两个线程,把他们当作两个人,都拉肚子,只有一个厕所,两人都必须要上这个厕所。

阻塞:

一个人先进去了,另外一个人在等待,另外一个人必须要等第一个人出来,才能进去搞事情,这个就是阻塞行为。

非阻塞:

强调没有一个线程可以妨碍其他线程去执行任务。所有线程都会尝试不断前向执行。后面会有更详细的描述。

死锁,饥饿,活锁
死锁:

一个单行道,有一个车,正在往前驾驶,然后有一个车从反方向驾驶过来,这两个谁都不想退,那么这个状态将会一直这样维持下去。线程如果发生这种类似的行为,那么就可能会造成死锁。

饥饿:

某个线程或者多个线程因为某些原因无法获得所需要的资源,比如有一个特大的饼,有很多人都想要吃,武力值高的肯定先吃,但是武力值高的人太多,导致那些武力值极低的人,会一直吃不到,这个就像等于线程中的优先级,优先级高的优先去做某事。跟死锁相比,饥饿还是会在某一段时间解决的,比如武力值高的都吃饼吃饱了,就到武力值低的去吃了。

活锁:

过马路的时候可能碰到这种情况,你往前走,有一个人骑着自行车往你这个方向驶来,他看到你了,你看到他了,你想让他,他想让你,你往左,他往右,你往右,他往左,两个一直保持着礼让的态度,就会一直这样来回重复做这样的事情。现实中还好说,人可以去交流,几次过后就解决了,但是对于线程,如果没有给线程赋予这种处理的思路,它就可能一直重复和另一个线程做这种“礼让”的事情,导致没有一个线程可以同时拿到所有资源去正常执行任务。

并发级别:

由于临界区的存在,我们必须控制多线程间的并发,根据控制并发的测率,我们可以把并发的级别进行分类,大致上可以分为:阻塞~无饥饿~无障碍~无锁~无等待五种。

阻塞:

java中的synchronized关键字,都会试图去得到临界区的锁,如果得不到,线程就会被挂机等待,知道占有了资源为止。是一种悲观策略,认为肯定会有线程去抢资源,一个线程抢到资源,其他的就会挂起等待执行完毕,再去试探。

无饥饿:

公平锁,不管优先级多高,讲究的是先来后到,这样所有的线程都有机会去执行。

无障碍:

是一种乐观策略,认为不会有线程去抢资源,无障碍的去执行,如果检测到冲突,就回滚。

无锁:

保证有一个线程能在有限步内完成操作离开临界区。

无等待:

要求所有线程必须在有限步内完成操作。

线程的三个特性:
原子性:

指的是一个操作不可中断,哪怕多个线程同时操作一个变量,每个线程只改它要改的值,不管被其它线程修改成什么值。

可见性:

并行多线程修改了某一个共享变量的值,其他线程并不一定能够立即知道这个修改。

有序性:

程序在执行的时候,程序的代码执行顺序和语句的顺序是一致的,在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到串行程序的执行,却会影响到多线程并发执行的正确性。

指令重排:
代码语言:javascript
复制
 1/**
 2 * @program: test
 3 * @description: 
 4 * @author: Mr.Yang
 5 * @create: 2018-11-06 11:22
 6 **/
 7public class A {
 8    int a=0;
 9    boolean flag=false;
10    public void  write(){
11        a=1;
12        flag=true;
13    }
14    public void reader(){
15        if(flag){
16            int i =a+1;
17        }
18    }
19}

假设线程A先执行writer方法,接着线程B执行reader()方法,如果发生指令重排,线程B在第11行代码,不一定能看到a被赋值1了。

指令重排的原因:

提高性能。可以共同执行任务,不需要等待第一个执行完成之后再去执行另一个任务。如果做成要任务执行完成再去执行另外一个,那么就和串行无太大区别了,性能也会严重受损。

一些指令是不能重排的:Happen-Before规则
程序顺序原则:
  • 一个线程内保证代码正常顺序执行
  • volatile规则:volatile变量的写,先发生与读,保证了volatile的可见性
  • 锁规则:解锁必然发生在随后的加锁前
  • 传递性:A引用B,B引用C,那么C必然先在A前执行。
  • 线程的start()方法先于它的每一个动作
  • 线程的所有操作先于线程的完结
  • 线程的中断先于被中断线程的代码
  • 对象的构造函数执行和结束先于finalize()方法
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JAVA知识总结与分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 并发与并行的区别:
    • 并发:两个任务或者多个任务执行,多个任务交替执行
      • 并行:两个任务或者多个任务一起同时执行
        • 例子:
          • 临界区:
            • 阻塞非阻塞:
              • 阻塞:
                • 非阻塞:
                • 死锁,饥饿,活锁
                  • 死锁:
                    • 饥饿:
                      • 活锁:
                      • 并发级别:
                        • 阻塞:
                          • 无饥饿:
                            • 无障碍:
                              • 无锁:
                                • 无等待:
                                • 线程的三个特性:
                                  • 原子性:
                                    • 可见性:
                                      • 有序性:
                                        • 指令重排:
                                          • 指令重排的原因:
                                            • 一些指令是不能重排的:Happen-Before规则
                                              • 程序顺序原则:
                                              领券
                                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档