java多线程问题

概览

在这里插入图片描述

java多线程知识点总结

1.什么是进程和线程
进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源
线程:CPU调度的最小单位,必须依赖进程而存在。
2. 新起线程方法
两种方法:继承类Thread
实现接口 Runnable
为什么要类,也要接口。因为JAVA单继承,类只能继承一个
接口 Callable  与Runnable 区别:Callable 有返回值
3.怎么样才能让Java里的线程安全停止工作呢
线程自然终止:自然执行完或抛出未处理异常stop(),resume(),suspend()已不建议使用,stop()会
导致线程不会正确释放资源,suspend()不释放资源容易导致死锁。

java线程是协作式,而非抢占式
   调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程
打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。
   isInterrupted() 判定当前线程是否处于中断状态。
   static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false。
   方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,如果确实是需要
中断线程,要求我们自己在catch语句块里再次调用interrupt()。
所有阻塞方法都会抛出InterruptedException
4.一个线程的生命周期(线程的方法)
新建线程调用start()方法进入就绪状态,cpu分配或join()方法获取执行权进入运行状态,
调用sleep()或wait()进入阻塞状态,sleep时间到或调用notify,notifyAll方法进入就绪状态,
运行时还可以调用yield方法让步进入就绪状态进行重新争抢cpu

在这里插入图片描述

5.调用yield() 、sleep()、wait()、notify()等方法对锁有何影响?
线程在执行yield()以后,持有的锁是不释放的

sleep()方法被调用以后,持有的锁是不释放的

调动方法之前,必须要持有锁。调用了wait()方法以后,锁就会被释放,当wait方法返回的时候,线程会重新持有锁

调动方法之前,必须要持有锁,调用notify()方法本身不会释放锁的
6.守护线程是什么
和主线程共死,finally不能保证一定执行
在start之前setDaemon(true);设置守护线程,主线程运行完,子线程也结束。
7.synchronized内置锁
对象锁,锁的是类的对象实例
类锁 ,锁的是每个类的的Class对象,每个类的的Class对象在一个虚拟机中只有一个,所以类锁也只有一个。
8.volatile关键字
适合于只有一个线程写,多个线程读的场景,因为它只能确保可见性。
9.ThreadLocal
ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,
各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不同的变量值
完成操作的场景。 ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

该类中方法有

 public T get() { }
 public void set(T value) { }
 public void remove() { }
 protected T initialValue() { }
get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,
remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,
一般是用来在使用时进行重写的,它是一个延迟加载方法,
ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值。
线程变量。可以理解为是个map,类型 Map<Thread,T>
10.CountDownLatch
作用:是一组线程等待其他的线程完成工作以后在执行,加强版join
await用来等待,countDown负责计数器的减一
11.CyclicBarrier
让一组线程达到某个屏障,被阻塞,一直到组内最后一个线程达到屏障时,屏障开放,
所有被阻塞的线程会继续运行CyclicBarrier(int parties)
12.Semaphore
控制同时访问某个特定资源的线程数量,用在流量控制
13.Exchange
两个线程间的数据交换
14.CAS的原理
CAS(Compare And Swap),指令级别保证这是一个原子操作
基本思路:如果地址V上的值和期望的值A相等,就给地址V赋给新值B,如果不是,不做任何操作。
CAS可以有效的提升并发的效率,但同时也会引入ABA问题。
ABA问题可加入版本号进行标识是否有变更
从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
15.Lock接口和synchronized的比较
synchronized jvm级别的锁,代码简洁,Lock:Java语言级别的锁,获取锁可以被中断,超时获取锁,尝试获取锁,
读多写少用读写锁
16.可重入锁ReentrantLock中所谓锁的公平和非公平有什么区别
如果在时间上,先对锁进行获取的请求,一定先被满足,这个锁就是公平的,不满足,就是非公平的

非公平的效率一般来讲更高

节约了从挂起(排队)到拿锁的时间
17.AQS是什么

AbstractQueuedSynchronizer

实质上用双向链表实现同步队列

用AQS实现同步,首先线程获取同步状态失败时,生成note节点加入同步队列尾部(用CAS设置),
判断前驱是否为首节点,是的话尝试获取同步状态,获取成功将其设置为首节点,获取不成功进入等待队列,
再去尝试获取同步状态

竞争失败的线程会打包成Node放到同步队列

注:AQS实质上拥有一个同步队列和多个等待队列,具体对应关系如下图所示:
在这里插入图片描述
上边为同步队列 双向链表
下边为condition等待队列 单向链表
Await从同步队列移动到等待队列等待
Signal从等待队列移动到同步队列争抢锁

18.Concurrenthashmap实现原理
1.7及之前: ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。
Segment实际继承自可重入锁(ReentrantLock),在ConcurrentHashMap里扮演锁的角色;HashEntry则用于存储
键值对数据。
一个ConcurrentHashMap里包含一个Segment数组,每个Segment里包含一个HashEntry数组,
我们称之为table,每个HashEntry是一个链表结构的元素。

1.8
1、 取消了segment数组,直接用table保存数据,锁的粒度更小,减少并发冲突的概率。
2、 存储数据时采用了链表+红黑树的形式,纯链表的形式时间复杂度为O(n),红黑树则为O(logn),
性能提升很大。什么时候链表转红黑树?当key值相等的元素形成的链表中元素个数超过8个的时候。

主要数据结构和关键变量
Node类存放实际的key和value值,hash ,next
sizeCtl:
负数:表示进行初始化或者扩容,-1表示正在初始化,-N,表示有N-1个线程正在进行扩容
正数:0 表示还没有被初始化,>0的数,初始化或者是下一次进行扩容的阈值
TreeNode 用在红黑树,表示树的节点, TreeBin是实际放在table数组中的,代表了这个红黑树的根。

在高并发下的情况下如何保证取得的元素是最新的?

答:用于存储键值对数据的HashEntry,在设计上它的成员变量value等都是volatile类型的,这样就保证别的线程对value值的修改,get方法可以马上看到。

问ConcurrentHashMap如何在保证高并发下线程安全的同时实现了性能提升?

答:ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,只要多个修改操作发生在不同的段上,它们就可以并发进行。



							-----------华丽分割线----------------


单例模式下volatile 关键字的分析

*DCL(双端j检锁机制)*并不一定是线程安全的,原因是有指令重排的存在,加入volatile可以禁止指令重排
在这里插入图片描述
Java语言规范规定,对于每一个类或者接口,都有一个唯一的初始化锁与之对应,
Java多线程类初始化过程为4个阶段

一、获取Class对象的初始化锁
获取Class对象的初始化锁来控制类或者接口的初始化过程,这个锁是线程阻塞的(即A获取了锁,B线程就会等待)
二、获得了锁的线程A进行初始化
执行类的静态初始化:
1.分配内存空间
3.地址赋值给引用变量
2.初始化对象
注意:这里虽然2.3重排序,但是其他线程不可见,这是处理器对其做的优化
三、线程A初始化完成,然后唤醒其他等待的线程
这里A的初始化处理过程完成
四、其他线程B结束
其他线程B获得锁后,读到类已经初始化过了,则结束

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值