线程池
2018-12-23 本文已影响0人
wanggs
1、为什么用线程池?
- 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
- 根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务
器累趴下(每个线程需要大约 1MB 内存,线程开的越多,消耗的内存也就越大,最后死机)
2、线程池参数的意思?
比如去火车站买票, 有10个售票窗口, 但只有5个窗口对外开放. 那么对外开放的5个窗口称为核心线程数, 而最大线程数是10个窗口.如果5个窗口都被占用, 那么后来的人就必须在后面排队, 但后来售票厅人越来越多, 已经人满为患, 就类似于线程队列已满.这时候火车站站长下令, 把剩下的5个窗口也打开, 也就是目前已经有10个窗口同时运行. 后来又来了一批人,10个窗口也处理不过来了, 而且售票厅人已经满了, 这时候站长就下令封锁入口,不允许其他人再进来, 这就是线程异常处理策略.而线程存活时间指的是, 允许售票员休息的最长时间, 以此限制售票员偷懒的行为
3.ThreadPoorExecutor原理?
image.png 20180419002550514.jpg// 无边界队列,没有长度
ConcurrentLinkedQueue clq = new ConcurrentLinkedQueue();
// 入队
clq.add(1);
clq.add(2);
clq.add(3);
// 出对 并且在队列中移除
System.out.println(clq.poll());
System.out.println("队列数: " + clq.size());
// 出对 不在队列移除
System.out.println(clq.peek());
System.out.println("队列数: " + clq.size());
/**
* 输出:
* 1
* 队列数: 2
* 2
* 队列数: 2
*/
// 有界队列
BlockingDeque bd = new LinkedBlockingDeque(2);
// 入队
bd.add(1);
bd.add(2);
System.out.println(bd.poll());
// 3秒内是否放入进去
bd.offer(3,3, TimeUnit.SECONDS);
// 出对 并且在队列中移除
System.out.println(bd.poll());
System.out.println(bd.poll());
System.out.println(bd.poll());
/**
* 1
* 2
* 3
* null
*/
image.png
4、线程池实现
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(1,2,3,TimeUnit.SECONDS,new LinkedBlockingDeque<>(1));
tpe.execute(new ThreadTest());
tpe.execute(new ThreadTest());
tpe.execute(new ThreadTest());
tpe.shutdown();
/**
* pool-1-thread-1
* pool-1-thread-2
* pool-1-thread-1
*/
}
5、线程池实现
- 定长
ThreadPoolExecutor tpe = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
tpe.execute(new ThreadTest());
tpe.execute(new ThreadTest());
tpe.execute(new ThreadTest());
tpe.shutdown();
- 缓存
ThreadPoolExecutor tpe = (ThreadPoolExecutor) Executors.newCachedThreadPool();
tpe.execute(new ThreadTest());
tpe.execute(new ThreadTest());
tpe.execute(new ThreadTest());
tpe.shutdown();
- 定时
ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
for (int i = 0; i < 10; i++) {
ses.schedule(new ThreadTest(), 3, TimeUnit.SECONDS);
}
ses.shutdown();
/**
* 3秒之后执行
* pool-1-thread-1
* pool-1-thread-2
* pool-1-thread-1
* pool-1-thread-2
* pool-1-thread-1
* pool-1-thread-2
* pool-1-thread-2
* pool-1-thread-1
* pool-1-thread-2
* pool-1-thread-1
*/
}
- 单例
ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(new ThreadTest());
es.execute(new ThreadTest());
es.execute(new ThreadTest());
es.shutdown();
/**
* pool-1-thread-1
* pool-1-thread-1
* pool-1-thread-1
*/
image.png
6、用过threadlocal吗?怎么用的
订单处理包含一系列操作: 减少库存,增加一条流水账,修改总账,这几个操作要在同一个事务中操作,通常也就是在一个线程中处理,如果累加公司操作失败了,应把前面操作的回滚 ,否则提交所有操作,这要求这些操作使用相同的数据库连接对象,,而这些操作代码不在一个模块中。
- ThreadLocal 的作用和目的: 用于实现线程内的数据共享,即相同的程序代码,在多个模块中运行,要共享同一份数据
- 每个线程调用全局的ThreadLocal对象的set方法,首先根据当前的线程获取ThreadLocalMap对象,然后在map中掺入数据,key其实是ThreadLocal对象,vale 是各自方法传入的参数,
7, volatile
共享变量的可见性
image.png每个线程都有自己本地的内存空间,线程执行的时候先把变量从内存中读取到自己的内存空间中,然后对变量进行操作,对变量操作完成后,在某个时间再把变量刷新到主内存中
public class TestVolatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
}
- 参考