线程相关

2019-12-23  本文已影响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,创建线程池的工厂类,它的工厂方法:

16、ThreadPoolExecutor 线程池标准实现

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

猜你喜欢

热点阅读