7_尚硅谷面试 第二季 -线程池

callable 接口
public class TestCallable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<>(new MyCallable());
        FutureTask<Integer> task1 = new FutureTask<>(new MyCallable());
        new Thread(task,"aa").start();
        new Thread(task1,"bb").start(); //输出两次
       // new Thread(task,"bb").start();//只会输出一次
        task.get(); //aa come in call
        task.get(); //最好放到最后 这里会阻塞主线程
    }
}
class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {

        System.out.println(Thread.currentThread().getName() + " come in call");
        TimeUnit.SECONDS.sleep(5);
        return 1024;
    }
}
线程优势
线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行
主要特点:
线程复用;控制最大并发数;管理线程
第一:
	降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:
	提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行
第三:
	提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
Executors
public class TestThreadPool {

    public static void main(String[] args) {
       // ExecutorService executor =  Executors.newFixedThreadPool(5); //固定五个线程轮流使用
       // ExecutorService executor =  Executors.newSingleThreadExecutor(); //只有一个线程
        ExecutorService executor =  Executors.newCachedThreadPool(); //有N个线程
        try{
            for (int i = 0; i < 10_00; i++) {
                executor.execute(()->{
                    System.out.println(Thread.currentThread().getName());
                });
            }
        }finally {
            executor.shutdown();
        }

    }
}
Executors.newFixedThreadPool()
    /**
     * 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>());
    }
    
	主要特点:
		1. 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
		2. newFixedThreadPool创建的线程池 corePoolSize 和 maximumPoolSize值相等的,它使用的是LinkedBlockingQueue
Executors.newSingleThreadExecutor()
    /**
     * 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>()));
    }
主要特点:
	1. 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行
	2. newSingleThreadExecutor 将corePoolSize 和 maximumPoolSize 都设置为 1,使用的是LinkedBlockingQueue
Executors.newCachedThreadPool()
    /**
     * 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>());
    }

主要特点:
	1. 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
	2. newCachedThreadPool 将corePoolSize 设置为0 ,将 maximunPoolSize 设置为Integer.MAX_VALUE,使用的SynchronousQueue
	    也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程
实际使用哪个
这仨都不用
阿里手册:
4. 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这
样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下: 1) FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 2) CachedThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM
线程池七大参数
    public ThreadPoolExecutor(int corePoolSize, //核心线程数
                              int maximumPoolSize, //最大线程数
                              long keepAliveTime, // 存活时间
                              TimeUnit unit, // 存活时间单位
                              BlockingQueue<Runnable> workQueue, // 阻塞队列
                              ThreadFactory threadFactory, //线程工厂
                              RejectedExecutionHandler handler) //拒绝策略
  1. corePoolSize:线程池中的常驻核心线程数
  2. maximumPoolSize: 线程池能够容纳同时执行的最大线程数,此值必须大于等于1
  3. keepAliveTime:多余的空闲线程的存活时间,当前线程池数量超过 corePoolSize 时,当空闲时间达到keepAliveTime值 时,多余空闲线程会被销毁直到只剩下 corePoolSize 个线程为止
  4. unit:keepAliveTime 的单位
  5. workQueue:任务队列,被提交但尚未被执行的任务
  6. threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可
  7. handler:拒绝策略,表示当队列满了并且工作线程大于等于线程的最大线程数(maximumPoolSize)拒绝策略
线程池运行原理
  1. 在创建了线程池后,等待提交过来的任务请求
  2. 当调用execute()方法添加一个请求任务时,线程池会做如下判断
    2.1如果正在运行的线程数量小于 corePoolSize ,那么马上创建线程运行这个任务
    2.2 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列
    2.3 如果这时候队列满了且正在运行的线程数量还小于 maximumPoolSize ,那么还要创建非核心线程立即运行这个任务
    2.4 如果队列满了且正在运行的线程数量大于或者等于 maximumPoolSize ,那么线程池会启动饱和拒绝策略来执行
  3. 当一个线程完成任务时,它会从队列中取出下一个任务来执行
  4. 当一个线程无事可做超过一定时间时,线程池会判断:
    如果当前运行的线程数大于 corePoolSize ,那么这个线程就被停掉
    所以线程池的所有任务完成后线程会回到 corePoolSize 的大小
线程池拒绝策略
等待队列已经排满。并且线程池中的max线程也达到最大,无法继续为新任务服务,就需要拒绝策略处理这个问题
AbortPolicy(默认)
直接抛出异常(RejectedExecutionException)阻止系统正常运行
public class TestTP1 {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
        2,
                5,
                1L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
       try{
           for (int i = 0; i < 9; i++) {
               final int num = i;
               pool.execute(()->{
                   System.out.println(Thread.currentThread().getName() + " " + num);
               });
           }
       }finally {
           pool.shutdown();
       }
    }
}
/**
pool-1-thread-1 0
pool-1-thread-4 6
pool-1-thread-5 7
pool-1-thread-3 5
pool-1-thread-2 1
pool-1-thread-5 4
pool-1-thread-4 3
pool-1-thread-1 2
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.test.TestTP1$$Lambda$1/379110473@28c97a5 rejected from java.util.concurrent.ThreadPoolExecutor@6659c656[Running, pool size = 5, active threads = 2, queued tasks = 0, completed tasks = 6]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.test.TestTP1.main(TestTP1.java:23)
*/
CallerRunsPolicy
调用者运行一种调节机制,该策略既不会摒弃任务,也不会抛出异常,而是将某些任务回退到调用者
public class TestTP1 {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
        2,
                5,
                1L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );

       try{
           for (int i = 0; i < 10; i++) {
               final int num = i;
               pool.execute(()->{
                   System.out.println(Thread.currentThread().getName() + " " + num);
               });
           }
       }finally {
           pool.shutdown();
       }

    }

}
/**
 * main 8
 * pool-1-thread-5 7
 * pool-1-thread-4 6
 * pool-1-thread-3 5
 * pool-1-thread-2 1
 * pool-1-thread-1 0
 * pool-1-thread-3 4
 * pool-1-thread-4 3
 * pool-1-thread-5 2
 * main 9
 */
DiscardOldestPolicy
抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交到当前任务
public class TestTP1 {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 5, 1L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy()
        );
       try{
           for (int i = 0; i < 10; i++) {
               final int num = i;
               pool.execute(()->{
                   System.out.println(Thread.currentThread().getName() + " " + num);
               });
           }
       }finally {
           pool.shutdown();
       }
    }
}
/**
 * pool-1-thread-1 0
 * pool-1-thread-4 6
 * pool-1-thread-3 5
 * pool-1-thread-2 1
 * pool-1-thread-3 9
 * pool-1-thread-4 8
 * pool-1-thread-1 4
 * pool-1-thread-5 7
 */
DiscardPolicy
直接丢弃任务,不予任何人处理也不抛出异常。如果允许丢失,这是最好的一种方案
public class TestTP1 {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 5, 1L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy()
        );
       try{
           for (int i = 0; i < 10; i++) {
               final int num = i;
               pool.execute(()->{
                   System.out.println(Thread.currentThread().getName() + " " + num);
               });
           }
       }finally {
           pool.shutdown();
       }
    }
}
/**
 pool-1-thread-1 0
 pool-1-thread-5 7
 pool-1-thread-4 6
 pool-1-thread-3 5
 pool-1-thread-2 1
 pool-1-thread-4 4
 pool-1-thread-5 3
 pool-1-thread-1 2
 */
线程池配置
CPU密集型
该任务需要大量运算,而没有阻塞,CPU一直全速运行
CPU密集任务只有真正的多核CPU上才能得到加速(通过多线程)
理论数量:
	CPU 核数 + 1 个线程的线程池
IO密集型
任务需要大量的IO,即大量的阻塞
在单线程上运行IO密集型的任务会导致浪费大量的CPU运算能力浪费在等待
所以在IO密集型任务中使用多线程可以大大的加速程序运行,即使在单核CPU上,这种加速主要就是利用了被浪费的阻塞时间
IO密集型时,大部分线程都在阻塞,因此需要多配置线程数:
	1. CPU核数 * 2
	2. CPU核数 / (1 - 阻塞系数)  阻塞系数在 0.8 ~ 0.9 之间
死锁定位
模拟死锁
public class TestDeadLock {
    public static void main(String[] args) {
        System.out.println(System.getProperties());
        String lock1 = "lock1";
        String lock2 = "lock2";
        new Thread(new My(lock1,lock2)).start();
        new Thread(new My(lock2,lock1)).start();
    }
}

class My implements  Runnable{
    private String lock1;
    private String lock2;

    public My(String lock1, String lock2) {
        this.lock1 = lock1;
        this.lock2 = lock2;
    }

    @Override
    public void run() {

        synchronized (lock1){
            System.out.println(Thread.currentThread().getName() + " 获取的锁是:" + lock1 +" 尝试获取的锁是:" + lock2 );
            synchronized (lock2){

            }
        }

    }
}

输入 jps 无输出问题
https://blog.csdn.net/lingyiwin/article/details/123238600

解决
1.输入 jps -l 获取到PID
	PS D:\project\sql_demo> jps -l
	23328 sun.tools.jps.Jps
	22712 org.jetbrains.jps.cmdline.Launcher
	21964 org.example.sqlddemo.TestDeadLock 
2. jstack 21964 
			"DestroyJavaVM" #22 prio=5 os_prio=0 tid=0x0000000002de4800 nid=0x3820 waiting on 	condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" #21 prio=5 os_prio=0 tid=0x0000000020829000 nid=0x230 waiting for monitor entry [0x00000000218ce000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.example.sqlddemo.My.run(TestDeadLock.java:32)
        - **waiting to lock <0x000000076e1103d0>** (a java.lang.String)
        - *locked <0x000000076e110408>* (a java.lang.String)
        at java.lang.Thread.run(Thread.java:745)

"Thread-0" #20 prio=5 os_prio=0 tid=0x0000000020800000 nid=0x448 waiting for monitor entry [0x00000000217cf000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.example.sqlddemo.My.run(TestDeadLock.java:32)
        - *waiting to lock <0x000000076e110408>* (a java.lang.String)
        - **locked <0x000000076e1103d0>** (a java.lang.String)
        at java.lang.Thread.run(Thread.java:745)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值