美文网首页
线程相关

线程相关

作者: 瑜小贤 | 来源:发表于2019-12-23 19:12 被阅读0次

    1、用多线程的目的是什么?

    充分利用cpu资源,并发做多件事

    2、单核cpu机器上适不适合用多线程?

    适合,如果是单线程,线程中需要等待IO时,CPU就会空闲出来

    3、线程什么时候会让出CPU?

    1. 阻塞时,wait、await、等待IO
    2. Sleep时。注:sleep抢到的锁是不会释放的
    3. yield。把CPU让出来,大家再抢占CPU资源的方法。
    4. 结束了

    4、线程是什么?

    一条代码执行流,完成一组代码的执行。
    这一组代码,我们往往称为一个任务。

    5、创建线程的方式有几种?

    一种,new Thread

    6、"任务"有几种写法?

    实现Runnable接口
    创建Callable实例
    集成Thread,修改run方法

    7、CPU做的是什么工作?

    执行代码,处理指令

    8、线程是不是越多越好?

    不是。因为
    1、线程在java中是一个对象,每一个java线程都需要一个操作系统线程支持。线程创建销毁需要时间。如果 创建时间+销毁时间>执行任务时间 就很不合算。
    2、线程过多,会消耗很多的内存。java对象占用堆内存,操作系统线程占用系统内存,根据jvm规范,一个线程默认最大(64位)栈大小为1m(超了报OOM),这个栈控件是需要从系统内存中分配的。
    3、操作系统需要频繁切换线程上下文(大家都想被运行),影响性能

    9、该如何正确使用多线程?

    多线程的目的:充分利用cpu并发做事(多做事)
    线程的本质:将代码送给cpu运行
    用合适数量的线程不断运送代码即可
    这个核实数量的线程就构成了一个池

    10、线程池原理?

    接收任务,放入仓库
    工作线程从仓库取任务,执行
    当没有任务时,线程阻塞,当有任务时,唤醒线程执行。
    (注:仓库用)

    11、仓库用什么?

    BlockingQueue阻塞队列,线程安全的
    在队列为空时的获取阻塞,在队列满时放入阻塞。
    BlockingQueue方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:
    第一种是抛出一个异常
    第二种是返回一个特殊值(null或false,具体取决于操作)
    第三种是在操作可以成功前,无限期地阻塞当前线程
    第四种是在放弃前 只在给定的最大时间限制内阻塞

    抛出异常 特殊值 阻塞 超时
    插入 add(e) offer(e) put(e) offer(e,time,unit)
    移除 remove() poll() take() poll(time,unit)
    检查 element() peak() 不可用 不可用

    12、手撸线程池

    public class FixedSizeThreadPool{
        //仓库
        private BlockingQueue<Runnable> taskQueue;
    
        //放线程的集合
        private List<Worker> workers;
    
        private volatile boolean working = true;//并发情况下变量的可见性
    
        public FixedSizeThreadPool(int poolSize, int taskQueueSize){
            if(poolSize <= 0 || taskQueueSize <= 0){
                throw new IllegalArgumentException("参数错误");
            }
    
            //初始化任务队列
            this.taskQueue = new LinkedBlockingQueue<>(taskQueueSize);
    
            //创建放线程的集合
            this.workers = new ArrayList<>();
        
            //初始化工作线程
            for(int i=0; i<poolSize;i++){
                Worker w = new Worker(this);
                this.workers.add(w);
                w.start();
            }
        }
    
        public boolean submit(Runnable task){
            return this.taskQueue.offer(task);
        }
    
        public void shutDown(){
            if(this.working){
                this.working = false;
                //如果工作线程处于阻塞状态的,唤醒
                for(Thread t : this.workers){
                    if(t.getState().equals(State.BLOCKED) || t.getState().equals(State.WAITING)){
                        t.interrupt(); //中断阻塞状态
                    }
                }
            }
        }
    
        //工作线程
        private class Worker extends Thread{
            private FixedSizeThreadPool pool;
            public Worker(FixedSizeThreadPool pool){
              this.pool = pool;
            }
    
            public void run(){
              //方便看效果,加个计数
              int taskCount = 0;
              //从仓库取任务执行
              while(this.pool.working || this.pool.taskQueue.size() > 0){
                  Runnable task  = null;
                  try{
                      if(this.pool.working){
                          task = this.pool.taskQueue.take();
                      }else{
                          task = this.pool.taskQueue.poll();
                      }
                  }catch(Exception e){
                      e.printStackTrace();
                  }
    
                  if(task != null){
                      try{
                          task.run();
                          System.out.println(Thread.currentThread().getName() + "执行完成" + (++taskCount) + "个任务");
                      }catch(Exception e){
                          e.printStackTrace();
                      }
                  }
              }
              System.out.println(Thread.currentThread().getName() + "结束");
            }
        }
    
    
        public static void main(String[] args){
            FixedSizeThreadPool pool  = new FixedSizeThreadPool(3, 5);
            //提交任务执行
            for(int i=0; i<5; i++){
                pool.submit(() -> {
                    System.out.println("任务开始...");
                    try{
                        Thread.sleep(2000L);
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                });
            }
    
            pool.shutdown();
        }
    }
    
    
    

    13、如何确定合适数量的线程?

    如果是计算型任务 --> cpu数量的1-2倍
    如果是IO型任务 --> 则需多一些线程,要根据具体的IO阻塞市场进行考量决定。
    如tomcat中默认的最大线程数为:200
    也可考虑根据需要在一个最小数量和最大数量间自动增减线程数

    14、java并发包中提供了哪些线程池的实现

    Executor void execute(Runnable command);
    ExecutorService ---- 加入了Callable、Future、关闭方法
    ForkJoinPool ---- 支持forkJoin框架的线程池实现(归并排序、外排序)
    ThreadPoolExecutor ---- 基础、标准的线程池实现
    ScheduledExecutorService ---- 对定时任务的支持
    Executors ---- 快速得到线程池的工具类

    15、慎用Executors,创建线程池的工厂类,它的工厂方法:

    • newFixedThreadPool(int nThreads)
      创建一个固定大小、任务队列容量无界的线程池。
      池的核心线程数 = 最大线程数 = nThreads
      高并发、多任务的场景不适用!

    • newCachedThreadPool()
      创建一个大小无界的缓冲线程池。他的任务队列是一个同步队列。任务加入到池中,如果池中有空闲线程,则用空闲线程执行,如无 则创建新线程执行。池中的线程空闲超过60秒,将被销毁释放。池中的线程数随任务的多少变化。
      池的核心线程数 = 0 最大线程数 = Integer.MAX_VALUE
      缓冲线程池适用于耗时较小的异步任务。

    16、ThreadPoolExecutor 线程池标准实现

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) 
    

    相关文章

      网友评论

          本文标题:线程相关

          本文链接:https://www.haomeiwen.com/subject/ikoznctx.html