线程篇知识点梳理

线程篇

线程安全的定义

当一个类被多个线程进行访问并且正确运行,它就是线程安全的

线程的分类

用户线程/守护线程

线程实现方式:

继承Thread类 。

实现Runnable接口 。

实现callable接口

应用程序可以使用Executor框架来创建线程池 。

Executors提供四种线程池

分别为: 

线程池名称

说明

newCachedThreadPool

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。定长线程池的大小最好根据系统资源进行设置。

newScheduledThreadPool

支持定时及周期性任务执行。

newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务

关闭线程:

Shutdown:空闲的线程interrupt,之前提交的任务可以继续执行/

shutdownNow:大部分都会被interrupt

线程池

线程池原理

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。

线程池特点:

 线程复用; 控制最大并发数; 管理线程

线程池组成

a线程管理器/

b工作线程/

c 任务接口/

d 任务队列/提供一种缓冲机制

线程池参数:

1 corePoolSize,线程池里核心线程数

2 maximumPoolSize,线程池里最大线程数量,超过最大线程时候会使用RejectedExecutionHandler

3 keepAliveTime, 空闲线程存活时间

4 unit,空闲线程存活时间单位

5 workerQueue,缓存异步任务的队列

6  threadFactory,用来构造线程池里的worker线程

7 handler拒绝策略

策略名称

说明

Abort

Policy

直接抛出异常,默认策略

Caller-Runs

用调用者所在的线程来执行任务

DiscardOldest

丢弃阻塞队列中靠最前的任务,并执行当前任务

Discard

直接丢弃任务

]

线程池方法

execute():提交任务,交给线程池执行

submit():提交任务,能够返回执行结果 execute + Future

execute与submit的区别:

shutdown():关闭线程池,等待任务都执行完

shutdownNow():关闭线程池,不等待任务执行完

getTaskCount():线程池已执行和未执行的任务总数

getCompletedTaskCount():已完成的任务数量

getPoolSize():线程池当前的线程数量

getActiveCount():当前线程池中正在执行任务的线程数量

线程的生命周期

// java.lang.Thread.State  引入后,点击State,即可看到源码

Java中的线程有6种状态分别是:

新建(new),/

运行(RUNNABLE),/

阻塞(BLOCKED)、/

[

等待阻塞(wait)/同步阻塞(lock)/其他阻塞(sleep|join)

]

等待(WAITING),/

等待超时(TIMED_WAITING),/

终止(TERMINATED)/

使用线程池 的好处

1>避免频繁地创建和销毁线程,达到线程对象的重用。

2>使用线程池还可以根据项目灵活地控制并发的数目。

线程的一些基本方法

Wait/ notify/notifyAll/ sleep/ join/yield/isAlive/activeCount/enumerate(枚举程序中的线程)/currentThread/

isDeamon/setDeamon/setName/setpriority(设置一个线程的优先级)/getpriority/countDownLatch(线程计数器)/CyclicBarrier/Semaphore(信号量)

方法比较:

1>wait和sleep

1.1>Wait=object类方法/Sleep=Thread类方法

1.2>最大的不同是在等待时wait会释放锁,而sleep一直持有锁。

1.3>Wait通常被用于线程间交互,sleep通常被用于暂停执行。

Join()/此方法可以让线程按顺序执行

LockSupport

当对象的等待队列中有多个线程时,notify只能随机选择一个线程唤醒,无法唤醒指定的线程

2>快速失败(fail-fast)和安全失败(fail-safe)

快速失败:当你在迭代一个集合的时候,如果有另一个线程正在修改你正在访问的那个集合时,就会抛出一个ConcurrentModification异常。

在java.util包下的都是快速失败。

安全失败:你在迭代的时候会去底层集合做一个拷贝,所以你在修改上层集合的时候是不会受影响的,不会抛出ConcurrentModification异常。

在java.util.concurrent包下的全是安全失败的。

3>synchronized和Lock

主要相同点:Lock能完成synchronized所实现的所有功能

主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。

3.1>Lock是一个类,synchronized是一个关键字

3.2>synchronized会自动释放锁,

Lock一定要求程序员手工释放,并且必须在finally从句中释放

4>Runnable和Callable的区别:

1>产生时间[Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的

]

2>方法区别[Callable规定的方法是call(),Runnable规定的方法是run()

]

1>返回值区别[Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void)]

2>异常区别[call方法可以抛出异常,run方法不可以]

3>运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

6>加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法。

5>synchronized和reentrantlock区别

1>实现方式不同[Synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的]

2>针对锁不同[ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁]

3>唤醒区别[ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程]

4>独特性[ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制]

Lock/unlock-try/finally结合

Yield方法可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行

线程的关键字

Volatile

特征:变量可变性/禁止重排序

使用场景:一个变量被多个线程共享

ThreadLocal:

定义:线程本地变量

使用场景: 数据库连接、 Session 管理等

ThreadLocalMap

ConcurrentHashMap == 分段锁

性能

使用比率

安全方面

修饰范围

是否阻塞

解决内容

Volatile(V)

轻量级实现,

V>S

S>V

volatile能保证数据的可见性,但不能保证原子性;

synchronized可以保证原子性,也可以间接保证可见性

变量

不会

变量在多个线程之间的可见性

Synchronized(S)

方法

多个线程之间访问资源的同步性

线程的终止方式

1 正常运行结束

2 使用退出标识推出线程

3 interrupt结束 线程

4 使用stop方法结束线程

对比对象

定义

应用场景

不足

实现

悲观锁

只允许一个线程访问

多写

  1. 多线程竞争下存在性能问题
  2. 一个线程持有锁会导致其它所有需要此锁的线程挂起

  1. 关键字:synchronized和ReentrantLock(重入锁)
  2. 数据库:select....for update

乐观锁

允许多个线程防范

多读

1循环时间长开销大

2只能保证一个共享变量的原子操作

1>cas算法

2>数据库:版本号机制

[

ABA问题的根本在于cas在修改变量的时候,无法记录变量的状态,比如修改的次数,否修改过这个变量。这样就很容易在一个线程将A修改成B时,另一个线程又会把B修改成A,造成casd多次执行的问题

]

>>死锁

定义:多个并发进程因争夺系统资源而产生相互等待的现象

避免死锁的方式:

1固定加锁的顺序(针对锁顺序死锁)

2开放调用(针对对象之间协作造成的死锁)

3使用定时锁-->tryLock()

>>自旋锁

短时间内释放资源,用户线程和内核的切换的消耗

>>同步锁

synchronized 它可以把任意一个非 NULL 的对象当作锁。 他属于独占式的悲观锁,同时属于可重入锁

>>ReentrantLock

默认为非公平锁。

可以唤醒指定条件的线程。

>>ReadWriteLock 读写锁

>>独占锁

>>共享锁

>>重量级锁

>>轻量级锁

>>偏向锁

>>分段锁

>>优化锁

[

-Xss参数用来控制线程的堆栈大小

在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。

异常没有被捕获该线程将会停止执行

信号量

]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值