线程间通讯方式

什么是线程安全?

线程的工作原理,jvm有一个main memory,而每个线程有自己的working memory,一个线程对一个variable进行操作时,都要在自己的working memory里面建立一个copy,
操作完之后再写入main memory。多个线程同时操作同一个variable,就可能会出现不可预知的结果。

而用synchronized的关键是建立一个monitor,这个monitor可以是要修改的variable也可以其他你 认为合适的object比如method,然后通过给这个monitor加锁来
实现线程安全,每个线程在获得这个锁之后,要执行完load到workingmemory -> use&assign -> store到mainmemory 的过程,才会释放它得到的锁。
这样就实现了所谓的线程安全。

线程安全就是说多线程访问同一块内存,不会产生不确定的结果。编写线程安全的代码是依靠线程同步。

CPU时间片轮转机制

cpu 给每个进程分配一个“时间段”,这个时间段就叫做这个进程的“时间片”,这个时间片就是这个进程允许运行的时间,如果当这个进程的时间片段结束,
操作系统就会把分配给这个进程的 cpu 剥夺,分配给另外一个进程。如果进程在时间片还没结束的情况下阻塞了,或者说进程跑完了,cpu 就会进行切换。
cpu 在两个进程之间的切换称为“上下文切换”,上下文切换是需要时间的,大约需要花费 5000~20000(5 毫秒到 20 毫秒,这个花费的时间是由操作系统决定)个时钟周期,
尽管我们平时感觉不到。所以在开发过程中要注意上下文切换(两个进程之间的切换)对我们程序性能的影响。

死锁

造成死锁的四个条件:

Read More

ThreadLocal原理

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,
对于其他线程来说则无法获取到数据。

源码分析

Thread中有一个成员变量:

1
ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocal的set方法中,如果当前Thread的threadLocals有值,则设置,没有则创建一个新的ThreadLocalMap。

Read More

ThreadPoolExecutor

参数

1
2
3
4
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, RejectedExecutionHandler handler);

  • corePoolSize: 线程池核心线程的数量;
  • maximumPoolSize: 线程池可创建的最大线程数量;
Read More

ThreadPoolExecutor原理分析

线程池状态

1
2
3
4
5
6
7
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;

当创建线程池后,初始时,线程池处于 RUNNING 状态;
如果调用了 shutdown()方法,则线程池处于 SHUTDOWN 状态,此时线程池不 能够接受新的任务,它会等待所有任务执行完毕;
如果调用了 shutdownNow()方法,则线程池处于 STOP 状态,此时线程池不能 接受新的任务,并且会去尝试终止正在执行的任务;
当线程池处于 SHUTDOWN 或 STOP 状态,并且所有工作线程已经销毁,任务缓 存队列已经清空或执行结束后,线程池被设置为 TERMINATED 状态。

任务的执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private final BlockingQueue<Runnable> workQueue;//任务缓存队列,用来存放等待执行的任务
private final ReentrantLock mainLock = new ReentrantLock();//线程池的主要状态锁,对线程池状态(比如线程池大小、runState 等的改变都要使用这个锁)
private final HashSet<Worker> workers = new HashSet<>();//用来存放工作集
private volatile long keepAliveTime;//线程存货时间
private volatile boolean allowCoreThreadTimeOut;//是否允许为核心线程设置存活时间
private volatile int corePoolSize;//核心池的大小(即线程池中的线程数目大于这 个参数时,提交的任务会被放进任务缓存队列)
private volatile int maximumPoolSize;//线程池最大能容忍的线程数

public int getPoolSize(){}//获取当前线程池的线程数量
private volatile RejectedExecutionHandler handler;//任务拒绝策略
private volatile ThreadFactory threadFactory;//线程工厂,用来创建线程
private int largestPoolSize;//用来记录线程池中曾经出现过的最大线程数
private long completedTaskCount;//用来记录已经执行完毕的任务个数

最核心的任务提交方法是 execute()方法,虽然通 过 submit 也可以提交任务,但是实际上 submit 方法里面最终调用的还是 execute()方法

Read More