第十六篇:进程与线程强化

1.1如何理解进程与线程?
进程:操作系统进行资源调度和分配基本单位(例如浏览器,APP,JVM)
线程:进程中的最小执行单位,同时也是CPU分配资源的最小基本单位
说明:多个线程可以共享所属进程的所有资源
1.2如何理解多线程中的并行与并发?
并发:多线程抢占CPU,可以不同时执行,侧重于多个任务交替执行
并行:线程可以不共享CPU,可每个线程一个CPU同时执行多个任务
总之:个人认为并行只出现在多个CPU或多核CPU中,而并发可理解为并行中的一个子集(并行中包含并发)
1.3如何理解线程的生命周期及状态变化?
一个线程从创建,运行,到最后销毁的这个过程称之为线程的生命周期,在这个生命周期过程中线程可能会经历如下几个状态:
这些状态可以归纳为:新建状态,就绪状态,运行状态,阻塞状态,死亡状态

2线程并发安全问题认知强化
2.1 如何理解线程安全与不安全?
多个线程并发执行时,仍旧能够保持数据的正确性,这种现象称之为线程安全
多个线程并发执行时,不能够保证数据的正确性,这种现象称之为线程不安全

2.2导致线程不安全的因素有哪些?
1.多个线程并发执行
2.多个线程并发执行时在共享数据(临界资源)
3.多个线程在共性数据集上的操作不是原子操作(不可拆分)

2.3如何保证并发线程的安全性?
1.对共享进行限制访问(例如加锁:syncronized,Lock)多线程在同步方法或在同步代码块上排队执行
2.基于CAS(比较和交换)实现非阻塞同步(基于CPU硬件技术支持)
3.取消共享,每个线程一个对象实例(例如threadlocal)
说明:Java中的线程安全问题的主要关注点有3个:可见性,有序性,原子性;Java内存模型(JVM)解决了可见性和有序性问题,而锁解决了原子性问题

2.4 Synchronized关键字应用及原理分析?
1.Synchronized简介:
1)syncronized是排它锁的一种实现,支持可重入性
2)基于这种机制可以实现多线程在共享数据集上同步(互斥和协作)
说明:
排他性:如果线程T1已经持有锁L,则不允许除T1外的任何线程T持有该锁L
重入性:如何线程T1已经持有锁L,则允许线程T1多次获取锁L,更确切的说,获取一次后,可多次进入锁

2.Synchronized应用分析?
1)修饰方法:同步方法(锁为当前实例或Class对象)
2)修饰代码块:同步代码块(代码块括号内配置的对象)

3.Synchronized原理分析:基于Monitor对象实现同步
1)同步代码块采用monitorenter,monitorexit指令显示的实现
2)同步方法则使用ACC_SYNCHRONIZED标记符隐式的实现

4.Synchronized锁优化:
为了减少获得锁和释放锁带来的性能消耗,JDK1.6以后的锁一共有4种状态,级别从低到高依次是:无锁状态,偏向锁状态,轻量级锁状态和重量级锁状态,这几种状态会随着竞争情况逐渐升级
说明:锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁,这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率

2.5.如何理解volatile关键字的应用?
1:定义:
1)多核或多CPU场景下保证共享变量的可见性
2)禁止指令的重排序操作
3)不保证原子性

2:应用场景分析:
1)状态标记(boolean类型属性)
2)安全发布(线程安全单例中的对象安全发布)
3)读写锁策略(一个写,并发读,类似读写锁)

2.7.如何理解JAVA中的悲观锁和乐观锁?
Java中为了保证多线程并发访问的安全性,提供了基于锁的应用,大体可归纳为两大类,即悲观锁和乐观锁
悲观锁&乐观锁定义说明:
1)悲观锁:假定会发生并发冲突,屏蔽一切可违法数据完整性的操作,同一时刻只能有一个线程执行写操作
例如Java中可以基于syncronized,Lock,ReadWriteLock等实现
2)乐观锁:假设不会发生冲突,只能提交操作时检查是否违反数据完整性,多个线程可以并发执行写操作但只能有一个线程写操作成功
例如Java中可借助CAS(Compare And Swap)算法实现(此算法依赖硬件CPU)

悲观锁&乐观锁应用场景说明:
1)悲观锁适合写操作比较多的场景,写可以保证写操作时数据正确
2)乐观锁适合读操作比较多的场景,不加锁的特点能够使其读操作的性能大幅提升

2.8.如何理解线程的上下文切换?
一个线程得到CPU执行的时间是有限的,当此线程用完为其分配的CPU时间以后,cpu会切换到下一个线程执行
在线程切换之前,线程需要将当前的状态进行保存,以便下次在次获得CPU时间片时可以加载对应的状态以继续执行剩下的任务,而这个切换过程是需要消费时间的,会影响多线程程序的执行效率,所以在使用多线程时要减少线程的频繁切换
减少多线程上下文切换的方案如下:
1)无锁并发线程:锁的竞争会带来线程上下文的切换
2)CAS算法:CAS算法在数据更新方面,可以达到锁的效果
3)使用最少线程:避免不必要的线程等待
4)使用线程:单线程完成多任务的调度和切换,避免多线程

2.9.如何理解死锁以及避免死锁问题?
多个线程互相等待已经被对方线程正在占用的锁,导致陷入彼此等待对方释放锁的状态,这个过程称之为死锁
如何避免死锁?
1)避免一个线程中同时获取多个锁
2)避免一个线程在一个锁中获取其他的锁资源
3)考虑使用定时锁来替换内部锁机制,如lock.tryLock(timeout)

3.0.如何理解进程与线程通讯?
线程通讯:Java中的多线程通讯主要是共享内存(变量)等方式
进程通讯:Java中进程通讯(IPC)主要是Socket,MQ等

3.1.如何实现进程内部线程之间的通讯?
3.1.1)基于wait/nofity/notifyall实现
1.wait()/notify()/notifyall()方法定义说明:
1)wait:阻塞正在使用监视器对象的线程,同时释放阀监视器对象
2)notify:唤醒在监视器对象上等待的单个线程,但不释放监视器对象,此时调用该方法的代码继续执行,知道执行结束才释放对象锁
3)notifyAll:唤醒在监视器对象上等待的所有线程,但不释放监视器对象,此时调用该方法的代码继续执行,知道执行结束才释放对象锁

2.wait()/notify()/notifyall()方法应用说明
1)这些方法必须应用在同步代码块或同步方法中
2)这些方法必须由监视器对象(对象锁)调用
说明:使用wait/notify/notifyAll的作用一般是为了避免轮询带来的性能损失

3.1.2基于Condition实现
1.Condition类定义说明
Condition是一个用于多线程间协同的工具类,基于此类可以方便的对持有锁的线程进行阻塞或唤醒阻塞的线程,它的强大之处在于它可以为多个线程间建立不同的Condition,通过signal()/signalall()方法指定要唤醒的不同线程

2.Condition类应用说明
1)基于Lock对象获取Condition对象
2)基于Condition对象的await()/signal()/signalall()方法实现线程阻塞或唤醒

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值