多线程复习

纯为个人认知:欢迎各路大佬指正

进程和线程的

1.定义

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

2.关系
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。

3.区别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

  1. 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

  2. 线程的划分尺度小于进程,使得多线程程序的并发性高。

  3. 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

  4. 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

  5. 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

4.优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移

进程和线程的区别

进程是资源分配的最小单位,线程是cpu调度的最小单位。

Thread中start和run方法的区别

调用start()方法会创建一个新的子线程并启动

run()方法只是Thread中的一个普通方式的调用

1、sleep和wait的区别
sleep是thread类的方法,而wait是object类中定义的方法
sleep方法可以用在任何顶峰
wait方法只能用在synchronized方法或者synchronized块中使用
Thread.sleep只会让出CPU,不会释放锁
Object.wait,不仅会让出CPU,而且会释放锁

2、线程的状态:新建、就绪、运行、阻塞、死亡、

3、获取线程返回值的几种方式

1、主线程等待法,利用属性赋值获取返回值,但是时间不能确定;

2、使用.join方式,等待子线程完成

3、通过实现Callable接口,利用isdone判断线程是否执行完毕,调用get获取返回值(推荐)

实现方式有	
3.1  通过 FutureTask执行
3.2  通过线程池,ExecutorService newThreadpopl= Executors.newCachedThreadPool();
				Future submit = newThreadpopl.submit(new myCallable());

4、调用wait方法,如果没有填写时间,则需要唤醒,使用notify和notifyAll,其中notify和notifyAll的区别

notifyAll会让所有处于等待池中的线程进入锁池,竞争锁

notify只会从等待池中随机抽取一个,进入锁池,竞争锁

5、volatile:保证可见性以及禁止重排,不能保证原子性

6、synchronized (互斥性)

简单理解:synchronize(object),给一个对象上锁,即修改object的markword信息、markword还存储GC信息以及hashcode

包含:对象锁、类锁

每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1。
如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

7、自旋锁

许多情况下,共享数据的锁定状态持续时间较短,切换线程不值得,通过让线程执行忙循环等待锁释放,不让出cpu。
缺点:若锁被其他线程长时间占用,会消耗更多的性能开销
可定义自旋次数

8、自适应自旋锁

自选的次数不再固定,由上一次在同一个锁上的自旋时间及锁的拥有者的状态来决定,自旋的次数。

9、锁升级 无锁=》偏向锁=》轻量级锁=》重量级锁

10、volatile和synchronized的区别

1)volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.

2)volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.

3)volatile仅能实现变量的修改可见性,而synchronized则可以保证变量的修改可见性和原子性.

  《Java编程思想》上说,定义long或double变量时,如果使用volatile关键字,就会获得(简单的赋值与返回操作)原子性。 
   
4)volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.

5、当一个域的值依赖于它之前的值时,volatile就无法工作了,如n=n+1,n++等。如果某个域的值受到其他域的值的限制,那么volatile也无法工作,如Range类的lower和upper边界,必须遵循lower<=upper的限制。

6、使用volatile而不是synchronized的唯一安全的情况是类中只有一个可变的域。

volatile为什么不是原子性

例如 i++操作
分成三步骤,三个步骤不是原子性的,所以volatile不能保证原子性
读取i(读取最新)
i+1
给i赋值

JUC包

AQS(AbstractQueuedSynchronizer:抽象队列同步器):采用内部维护了一个链表,以及一个state状态(判断是否有锁)

公平锁以及非公平锁:公平:即抢占资源时,先去排队,非公平,先抢一次,再排队。

CAS:操作包括三个操作数:需要读写的内存位置(V)、预期原值(A)、新值(B)。如果内存位置与预期原值的A相匹配,那么将内存位置的值更新为新值B。如果内存位置与预期原值的值不匹配,那么处理器不会做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS其实就是一个:我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

ReentrantLock
Reentranlock是基于cas(比较并且交换)+aqs(抽象队列同步器)做成的同步锁。加锁的过程如下,首先尝试获取锁,即利用cas思想将锁状态state由0变成1,如果抢到则独占锁,运行。如果没有,则根据条件加入等待队列。
ReentrantLock源码分析

ConcurrentHashMap
我就不多比比了,看别人的文章
ConcurrentHashMap源码分析

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值