java-thread-summary-2020-12-26

一.进程是怎么在操作系统中运行的?

1.同步机制应遵循的规则:

1.1空闲让进

当无进程处于临界区时,表明临界资源处于空闲状态,应允许一个请求进入临界区的进程立即进入自己的临界区,
以有效的利用临界资源。

1.2忙则等待

保证互斥访问临界资源。

1.3有限等待

对要求访问临界资源的进程,应保证在有限时间内进入自己的临界区,以免陷入"死等"状态。

1.4让权等待

当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入"忙等"。

二.java线程池中各参数的作用。

分配线程执行.png

1.workQueue

SynchronousQueue:没有容量,直接提交线程池执行。newCachedThreadPool线程池即使用的该队列。

ArrayBlockingQueue:有界队列,如果该队列已满,则将触发拒绝策略。

LinkedBlockingQueue:一个由链表组成的有界队列,此队列的默认长度为Integer.MAX_VALUE。

LinkedTransferQueue:一个由链表组成的无界阻塞队列。

PriorityBlockingQueue:该队列可以根据任务自身的优先级顺序执行。

2.拒绝策略policy

AbortPolicy:直接抛出异常,阻止系统正常工作。

CallerRunsPolicy:在调用者线程中运行当前被丢弃的任务。

DiscardOldestPolicy:丢弃最老的一个请求,也就是即将执行的一个任务,并尝试再次提交当前任务。

DiscardPolicy:该策略默默丢弃无法处理的任务,不予任何处理。

如以上策略仍然无法满足实际应用的需要,可以自己扩展RejectedExecutionHandler。

3.设置线程池数量

Ncpu=CPU的数量
Ucpu=目标cpu的使用率,0<=Ucpu<=1
W/C=等待时间与计算时间的比率

Nthreads=Ncpu * Ucpu * (1+W/C)

一般情况下io密集型意味着等待时间W会加大,所以核心线程数应该对Ncpu加倍,比如2*Ncpu;
cpu密集型意味着计算时间C会变大,那么按照公式算出来的核心线程数,就应该接近Ncpu。
Ncpu的个数可以通过以下代码获得:

Runtime.getRuntime().availableProcessors();

4.最大线程数-maximumPoolSize

线程池里面的线程数不能超过最大线程数。即最大线程里面包含核心线程。

三.锁

1.共享锁

是指锁可被多个线程所持有的,例如ReentrantReadWriteLock,写锁优先级高于读锁,且写时阻塞。但是,可有多个线程持有读锁。

2.可重入锁

是指同一个线程可以多次获取锁,如下图所示methodA内部调用methodB,如果synchronized不可重入,则会死锁。所以synchronized和ReentrantLock都是可重入锁。

public synchronized void mehtodA() throws Exception{
 // Do some magic tings
 mehtodB();
}

public synchronized void mehtodB() throws Exception{
 // Do some magic tings
}

3.乐观锁

比如cas,版本号机制。

乐观是指当你执行某项计算时,实际上没有使用互斥,但是在执行计算完成,并且你准备更新这个Atomic对象或者LongAdder对象时,你需要使用一个称为compareAndSet()的方法将旧值和新值一起提交给这个方法,如果旧值与它在Atomic对象中(即内存中的值)发现的值不一致,那么这个操作失败——这意味着某个其他任务已经于此操作执行期间修改了这个对象。- d

还有jpa中的@Version注解也是一种乐观锁。

参考资料:
a.《计算机操作系统》——汤子瀛 哲凤屏 汤小丹——Page 41
b.《实战Java高并发程序设计(第2版)》——葛一鸣——Page 110、112、113、119
c. https://mp.weixin.qq.com/s/l6ee7k0n7CCVFgBS4tI2kQ
d. Think in java——Page 762、760

你可能感兴趣的:(java-thread-summary-2020-12-26)