线程系列
1. 线程不安全的原因
java内存模型: 线程内存栈<---->堆 主存,之间的读取和写入导致多线程数据不一致问题
2. Java的线程安全
(1)使用synchronized
a.方法同步时,锁定object,若方法静态锁定class
b.synchronized(this)将在进入同步块前锁定对象
c.需要避免deadlock
d.锁会耗费资源,必需时在使用
e.常量池中数据不要加锁
(2)使用concurrent.atomic包中的AtomicWrapper类如AtomicInteger
(3)使用concurrent.locks包中的Lock
(4)使用线程安全类,concurrentHashMap
(5)使用volatile关键使每个线程从主存读取数据
3. 线程池
(1)核心类ThreadPoolExecutor:
参数:
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
• corePoolSize:核心池的大小,在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
• maximumPoolSize:线程池最大线程数;
• keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止;
• unit:参数keepAliveTime的时间单位(DAYS、HOURS、MINUTES、SECONDS 等)
• workQueue:阻塞队列,用来存储等待执行的任务;
○ ArrayBlockingQueue (有界队列)
○ LinkedBlockingQueue (无界队列)
○ SynchronousQueue
• threadFactory:线程工厂,主要用来创建线程
• handler:拒绝处理任务的策略
○ AbortPolicy:丢弃任务并抛出 RejectedExecutionException 异常。(默认这种)
○ DiscardPolicy:也是丢弃任务,但是不抛出异常
○ DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
○ CallerRunsPolicy:由调用线程处理该任务
uml图:
流程:
a. 如果currentPoolSize<corePoolSize,==>new Thread()
b.如果corePoolSize=<currentPoolSize<maxiumPoolSize
b1. 如果queue满了,==>new Thread()
b2. 如果queue未满, ==> task入queue
c.如果currentPoolSize>=maxiumPoolSize==>调用RejectedExecutionHandler
d.针对keepaliveTime,如果currentPoolSize>corePoolSize,则外面未使用的thread如果闲时>keepaliveTime==>停止thread()
(2)几种默认线程池
newFixedThreadPool: 使用无界blockQueue:linkedBlockingQueue【ReentrantLock】,每次任务进来,都要等待有线程空出来,否则多余任务入queue等待
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* {@code nThreads} threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadPool:使用无界blockQueue:linkedBlockingQueue,相当于1个corePoolSize的fixedThreadPool
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* {@code newFixedThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newCachedThreadPool:重复使用之前创建的thread如果还在,用于短命thread
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newScheduledThreadPool:定时执行
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @return a newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
/**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given core pool size.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}