java 多线程分段_java 多线程基础

本文深入探讨Java多线程,包括创建多线程、synchronized线程同步、volatile关键字的原理及应用。还介绍了线程安全与不安全的情况,详细讨论了Java并发工具,如CountDownLatch、Semaphore、CyclicBarrier,以及ReentrantLock、Condition、Callable和Future。此外,文章还涵盖了Fork/Join框架的工作原理和优缺点, BlockingQueue在生产者消费者模型中的作用,以及线程池ThreadPoolExecutor。最后,文章对比了HashMap和ConcurrentHashMap,并讲解了Atomic与CAS算法确保线程安全的重要性。
摘要由CSDN通过智能技术生成

1.创建多线程

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

2.synchronized线程同步机制

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

3.volatile关键字

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

Ø通俗地讲:volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时, 又会强迫线程将最新的值刷新到主内存。这样任何时刻,不同的线程总能看到该变量的最新值

AAffA0nNPuCLAAAAAElFTkSuQmCC

volatile

1.对变量的写操作不依赖当前值。

2.该变量没有包含在具有其他变量的式子中

特别适合作为状态标识量

另一个使用场景就是 使用两次

4.线程的安全与不安全

AAffA0nNPuCLAAAAAElFTkSuQmCC

5.java并发工具与连接池

juc CountDownLatch 倒计时锁

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

juc 之Semephore信号量

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

尝试获取许可 获取到了就执行 获取不到 直接放弃,上图就只能有三个线程执行。

juc之CyclicBarrier循环屏障

AAffA0nNPuCLAAAAAElFTkSuQmCC

只解决一个问题,就是让所有线程同时执行。

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

使用场景;

用于多线程计算数据,最后合并计算结果的计算场景。

AAffA0nNPuCLAAAAAElFTkSuQmCC

1.cpu评测软件。(所有线程同时开始)

2.零点零分双十一秒杀 (假设有20个奖品,设置20个线程去抽奖,在0点0分时必须同时跑,不能有先后顺序。)

3抢票软件。(在后车票开售时,就必须有300或500个线程同时跑进去抢票)

和countDownLatch区别:

countDownLatch:

1.计数器只能用一次。

2.实现一个或多个线程需要等待其他线程完成某项操作后,才能继续往下执行(描述的是一个或多个线程等待其他线程 关系)

CyclicBarrier :

1计数器可以重置(循环使用)

2.多个线程之间相互等待,知道所有线程都满足条件之后,才能继续执行后续操作(描述的是各个线程内部相互等待的关系,所以他能处理更复杂业务场景)。

juc之ReentrantLock重入锁(不太推荐使用)

AAffA0nNPuCLAAAAAElFTkSuQmCC

比如我们拿到文件锁之后 跳出去做其他事,在回来还可以获得这个文件锁,就是可重入锁。

AAffA0nNPuCLAAAAAElFTkSuQmCC

提高性能 是想尽办法 不让线程进入内核的阻塞状态。

总结  :

1.当只有少了竞争者时 synchronized (不会引发死锁,jvm 会自动解锁)是最佳选择

2.竞争者不少,但是线程增长的趋势是可以预估的这是推荐用ReentrantLock

juc 之Condition线程等待与唤醒

AAffA0nNPuCLAAAAAElFTkSuQmCC

任何需要预先设置好顺序的线程都需要Condition的支持

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

juc之Callable&Future

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

JUC-Fork/Join(jdk7 用于并行执行的框架) 框架

Fork/Join 是将大任务 分拆为若干个小任务,最终汇总每个小任务的结果后得到大任务结果的框架。fork---分拆,  join---合并。

采用的是 工作窃取算法(如下图)

AAffA0nNPuCLAAAAAElFTkSuQmCC

假如需要做一个比较大的任务,可以把这个任务 分割个若干个互不依赖的小任务,为了减少线程间的竞争,把这些子任务分别放到不通的队列里,为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应,比如A线程处理A队列里的任务,但是有的线程会先把自己队列里的任务处理完,而其他线程队列里还有任务需要处理,于是先处理完的线程回去其他未完成的队列里窃取任务,而这时多个线程会访问同一队列,为了减少任务线程和被窃取任务的线程间的竞争,通常我们会使用双端队列,被窃取任务的线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾巴获取任务。

优点;充分利用线程进行并行计算,并减少了线程见得竞争

缺点: 在某些情况下还是存在竞争(比如双端队列里只有一个任务时),更加消耗系统资源。

局现性

1任务只能用fork和join来作为同步机制,如果使用了其他同步机制 工作线程就不能执行其他任务了。

2.所拆分的任务 不应该执行io操作(如读和写数据文件)

3.任务不能抛出检查异常,必须通过必要代码处理

代码:

类必须继承RecursiveTask<>类

其中Recursive是递归的意思,就是把大任务不断拆分成小任务。

下面例子做相加运算(从1加到100),假设相加任务很耗时,所以将任务分解多线程相加

流程,首先拆分子任务,之后让子任务各自执行,最后同过join 的方式合并结果

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

JUC-BlockingQueue

线程安全,主要用于生产者和消费者模型

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

线程池

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

ThreadPoolExecutor

AAffA0nNPuCLAAAAAElFTkSuQmCC

如果运行线程数小于corePoolSize,直接创建新线程处理任务,如果线程池中线程数量大于corePoolSize且小于maximumpoolSize则只有当workQueue满了的时候 才会创建线程到maximumpoolSize值,来处理任务

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

HashMap与ConcurrentHashMap解析

HashMap

底层结构是  数组+链表

HashMap 有两个参数影响性能是初始容量(16)和加载因子(0.75)

加载因子是能达到最大容量,如16*0.75=12 当放入12个元素后HashMap就需要扩容为原来的2倍

AAffA0nNPuCLAAAAAElFTkSuQmCC

HashMap 的寻址方式:

对于一个新插入或需要读取的数据,HashMap需要将其key按照一定计算规则计算出hash值并对数组长度进行取模,结果作为在查找中的index

单线程下rehash

AAffA0nNPuCLAAAAAElFTkSuQmCC

多线程下rehash  (扩容) 容易出现死循环

ConcurrentHashMap(jdk7,基于分段锁处理的)

ConcurrentHashMap 底层结构任然是数组和链表,与HashMap不同的是最外层不是一个大数组而是一个Segment 数组

AAffA0nNPuCLAAAAAElFTkSuQmCC

与hashmap的不同点:

hashmap  线程不安全,如许key和value为空,不容许在遍历的时候修改

ConcurrentHashMap 线程安全 不如许key和value为空,如许遍历的时候修改,并且跟新对后面的遍历可见

java8下优化的ConcurrentHashMap  将底层数结构中的链表用了红黑树来提高并发性(默认并发数达到8时将链表变为红黑树)

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

juc之Atomic与CAS算法(乐观锁)

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

单例模式代码

/**

* 双重同步锁单例模式

* 限制程序  不让其发生指令重排(volatile  关键字可以限制不发生指令重排)

*/

public class SingletonExample5 {

//首先定义私有的构造方法(只有构造函数私有,才能保证外面不能通过new的方式不断创建对象出来)

public SingletonExample5() {

}

//1.memory=allocate  分配对象内存空间

//2.ctorInstance()  初始化对象

//3.Instance=memory  设置instance指向刚分配的内存

//在多线程下  jvm和cpu 优化,发生了指令重排

//1.memory=allocate  分配对象内存空间

//3.Instance=memory  设置instance指向刚分配的内存

//2.ctorInstance()  初始化对象

//下面 代码重排后 在线程a 执行第3步  给设置instance指向刚分配的内存

//但是 线程b 刚好执行到判断那步  就会直接返回instance对象,但是实际instance对象并没有初始化

//使用volatile可以限制指令重排  所以就是线程安全的

//单例对象 volatile+双重检测机制---》禁止指令重排

private volatile static SingletonExample5 instance=null;

//静态工厂模式(懒汉模式,就是第一次使用的时候创建)

public static SingletonExample5 getInstance(){

if(instance==null){//双重监测机制

synchronized(SingletonExample5.class){//同步锁

if (instance==null){

instance=new SingletonExample5();

}

}

}

return instance;

}

}

@Slf4j

@ThreadSafe

@Recommend

public class SingletonExample7 {

public SingletonExample7() {

}

public static SingletonExample7 getInstance(){

return Singleton..getInstance();

}

private enum  Singleton{

;

private  SingletonExample7 singlenton;

//jvm 保证只被调用一次

Singleton(){

singlenton=new SingletonExample7();

}

public SingletonExample7 getInstance(){

return singlenton;

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值