多线程理论、创建方式、线程池体系结构

多线程理论知识

一、线程模型

用户线程和内核线程

1、多对一模型

​ 多对一线程模型,又叫作用户级线程模型,即多个用户线程对应到同一个内核线程上,线程的创建、调度、同步的所有细节全部由进程的用户空间线程来处理

优点:

  • 用户线程的很多操作对内核来说都是透明的,不需要用户态和内核态的频繁切换,使线程的创建、调度、同步等非常快。

缺点:

  • 由于多个用户线程对应到同一个内核下线程,如果其中一个用户线程阻塞,那么该其他用户线程也无法执行。
  • 内核并不知道用户态有哪些线程,无法像内核线程一样实现较完整的调度、优先级等。

场景:

  • 许多语言实现的协程库基本上都属于这种方式,比如 python 的 gevent
2、一对一模型

​ 一对一模型,又叫作**内核级线程模型 **,即一个用户线程对应一个内核线程,内核负责每个线程的调度、可以调度到其他处理器上面。

优点:

  • 实现简单

缺点:

  • 对用户线程的大部分操作都会映射到内核线程上,引起用户态和内核态的频繁转换;
  • 内核为每个线程都映射调度实体,如果系统出现大量线程,会对系统性能有影响。

场景:

  • Java使用的就是一对一线程模型,所以在Java中启动一个线程要谨慎。
3、多对多模型

​ 多对多模型,又叫作两级线程模型,它是博采众长之后的产物,充分吸收前两种线程模型的优点尽量规避他们的缺点

​ 在此模型下,用户线程与内核线程是多对多的映射模型,通常用户线程大于等于内核线程

​ 首先,区别于多对一模型,多对多模型中的一个进程可以与多个内核线程关联,于是进程内的多个用户线程可以绑定不同的内核线程,这点和一对一模型相似;

​ 其次,又区别于一对一模型,它的进程里的所有用户线程并不与内核线程一一绑定,而是可以动态绑定内核线程,当某个内核线程因为其绑定的用户线程的阻塞操作被内核调用让出CPU时,其关联的进行中其余用户线程可以重新与其他内核线程绑定运行*

​ 所以,多对多模型即不是多对一模型那么完全靠自己调度的,也不是一对一模型完全靠操作系统调度的,而是中间态(自身调度与系统调度协同工作),因为这种模型的高度复杂性,操作系统内核开发者一般不会使用,所以更多的时候是作为第三方库的形式出现。

优点:

  • 兼具多对一的轻量
  • 由于对应了多个内核线程,则一个用户阻塞时,其他用户线程仍然可以执行
  • 由于对应了多个内核线程,则可以实现较完整的调度、优先级等

缺点:

  • 实现复杂

场景:

  • Go语言中的 goroutine 调度器就是采用的这种实现方案,在Go语言中一个进程可以启动成千上万个goroutine,这也是其出道以来就自带“高并发”光环的重要原因。
总结:
  • 线程为用户线程和内核线程
  • 线程模型又多度一模型、一对一模型、多对多模型
  • 操作系统一般只实现了一对一模型
  • Java使用的是一对一模型,所以它的一个线程对应于一个内核线程,调度完全交给操作系统来处理
  • Go语言使用的是多对多线程模型,这也是高并发的原因,它的线程模型与Java中的ForkJoinPool非常类似
  • Python的gevent使用的是多对一线程模型

参照:

二、线程创建的8种方式

1、继承Thread类
public class CreatingThread01 extends Thread {
    @Override
    public void run(){
        System.out.println(getName() + "is running");
    }
    
    public static void main(String[] args) {
        new CreatingThread01().start();
        new CreatingThread01().start();
        new CreatingThread01().start();
        new CreatingThread01().start();
    }
}
2、实现Runnable接口
public class CreatingThread02 implements RUnnable {
    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName() + "is running");
    }
    
    public static void main(String[] args) {
        new Thread(new CreatingThread02()).start();
        new Thread(new CreatingThread02()).start();
        new Thread(new CreatingThread02()).start();
        new Thread(new CreatingThread02()).start();
    }
}

3、匿名内部类
public class CreatingThread03 {
    public static void main(String[] args) {
        // thread 匿名类,重写Thread的run() 方法
        new Thread(){
            @Override
            public void run(){
                System.out.println(getName() + "is running");
            }
        }.start();
        
        // Runnable匿名类.实现其run()方法
        new Thread(new Runnable(){
        	@Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "is running");
            }
        }).start();
        
        // 同Runnable,使用lambda表达式函数式编程
        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "is running");
        }).start();
    }
}

4、实现Callabe接口
public class CreatingThread04 implements Callable<Long> {
    @Override
    public Long call() throws Exception {
        Thread.sleep(2000L);
        System.out.println(Thread.currentThread().getName() + "is running");
        return Thread.currentThread().getId();
    }
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    	FutureTask<Long> task = new FutureTask<>(new CreatingThread04());
    	new Thread(task).start();
    	System.out.println("等待任务完成");
     	Long result = task.get();
      	System.out.println("任务结果:" + result);
        
    }
}
5、定时器(java.util.Timer)
public class CreatingThread05 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //每一秒执行一次
        timer.schedule(new TimerTask(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "is running");
            }
        }, 0, 1000);
    }
}
6、线程池
  • 也叫螺纹池
public class CreatingThread06 {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        IntStream().range(0, 100).forEach(i -> {
            
			threadPool.execute(()->
            	System.out.println(Thread.currentThread().getName() + "is running");
			);
            
        });
    }
}
7、并行计算(Java8 + )
public class CreatingThread07 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        // 串行 ,打印结果为12345
        list.stream().froEach(System.out::print);
        System.out.println();
        
        // 并行,打印结果随机,比如 52341
        list.parallelStream().forEach(System.out.print);

            
    }
}
8、@EnabeAsync+@Async注解
  • 也称为弹簧异步方法

  • @EnableAsync、@Async是Spring支持的

// 为了方便用的SrpingBoot哈,反正主要能支持这个@EnableAsync注解节即可(Spring都支持)
@SpringBootApplication
@EnableASync	//开启Async
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

@Service
public class CreatingThread08Service {
    @Async
    public void call() {
        System.out.println(Thread.currentThread().getName() + "is running");
    }
}


// 开始测试,和直接用Service方法一样
@RunuWith(SptringRunner.class)
@SpringBootTest(classes = Application.class)
public class CreatingThread08Test {
    @Autowired
    private CreatingThread08Service creatingThread08Service;
    
    @Test
    public void test() {
        creatingThread08Servie.call();//task-3 is running;
        creatingThread08Servie.call();//task-2 is running;
        creatingThread08Servie.call();//task-1 is running;
        creatingThread08Servie.call();//task-4 is running;
    }
}

三、Java线程池-体系结构

结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-StcfExfy-1578881034130)(C:\Users\86134\AppData\Local\Temp\1578799027209.png)]

上面都是线程池中非常重要的接口和类

1、Executor:
  • 线程池顶级接口

  • public interface Executor {
        void execute(Runnable command);
    }
    
2、ExecutorService:
  • 线程池次级接口,对Executor做了一些扩展,增加了一些功能

  • 主要增加了关闭线程池、执行有返回值的任务、批量执行任务的方法

  • public interface ExecutorService extends Executor {
        // 关闭线程池,不再接受任务,但是已经提交的会执行
        void shutdown();
        // 立即关闭线程池,尝试停止正在运行的任务,未执行的任务将不再执行
        // 被强迫停止及未执行的任务将以列表的形式返回
        List<Runnable> shutdownNow();
        
        // 检测线程池是否已关闭
        boolean isShutdown();
        
        // 检测线程池是否已终止,只有在shutdown() 或 shutdownNow() 之后调用才有可能为true
        boolean isTerminated();
        
        // 在指定时间内 线程达到终止状态了才会返回true
        boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
        
        // 执行有返回值的任务,任务的返回值为task.call()的结果
        <T> Future<T> submit(Callable<T> task);
        
        // 执行有返回值的任务,任务的返回值为这里传入的result
        // 当然只有当任务执行完成了调用get() 时才会返回
        <T> Future<T> submit(Runnable task, T result);
        
        // 执行有返回值的任务,任务的返回值为null
        // 当然只有当任务执行完成了调用 get() 时才会返回
        Future<T> submit(Runnable task);
        
        // 批量执行任务,只要当这些任务都完成了这个方法才会返回
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) 
            throws InterruptedException;
        
        // 在执行时间内批量执行任务,未执行完成的任务将被取消
        // 这里的timeout 是所有任务的总时间,不是单个任务的时间
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) 
            throws InterruptedException, ExecutionException;
        
        // 返回任意一个已完成任务的执行结果,未执行完成的任务将被取消
        <T> T invokeAny(Collection<? extends Callable<t>> tasks)
            throws InterruptedException, ExecutionException;
        
        // 在执行时间内如果有任务完成,则返回任意一个已完成任务的执行结果,
        // 未执行完成的任务将被取消
        <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
            throw InterruptedException, ExecutionException, TimeoutException;
        
    }
    
3、ScheduledExecutorService:
  • 对ExecutorService做了一些扩展,增加了一些定时任务相关的功能

  • 包含2大类:执行一次,重复多次执行

  • public interface ScheduledExecutorService extends ExecutorService {
        
        // 在指定延时后执行一次
        public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
        
        // 在指定延迟后执行一次
        public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                               long delay, 
                                               TimeUnit unit);
        // 在指定延迟手开始执行,并在之后以指定=时间间隔=重复执行(间隔不包含任务执行时间)
        // 相当于之后的延时以==任务开始==计算
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, 
                                                     long initialDelay,
                                                     long period,
                                                     TimeUnit unit);
     
        // 在指定延迟后开始执行,并在之后以指定是=延时=重复执行,
        // 相当于之后的延时以==任务结束==计算
        public ScheduledFuture<?> scheduledWithFixedDelay(Runnable command,
                                                         long initialDelay,
                                                         long delay,
                                                         TimeUnit unit);
        
    }
    
4、AbstractExecutorService:
  • 抽象类,运用模板方法设计模式实现了一部分方法

  • public abstract class AbstractExecutorService implements ExecutorService {
        /** 
         * 实现了ExecutorService接口以下方法 
         */
        public Future<?> submit(Runnable task);
        public <T> Future<T> submit(Runnable task, T result);
        public <T> Future<T> submit(Callable<T> task);
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks);
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                               long timeout, TimeUnit unit);
        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks);
        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                             long timeout, TimeUnit unit);
        
        /**
         * 自己内部方法
         */
        
        
        protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
            return new FutureTask<T>(runnable, value);
        }
        protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
            return new FutureTask<T>(callable);
        }
    }
    
5、ThreadPoolExecutor:
  • 普通线程池类,也就是我们平时说的线程池类,包括最基本的线程池操作相关的方法实现;
  • 线程池的主要实现逻辑都在这里面,比如线程的创建、任务的处理、拒绝策略等
6、ScheduledThreadPoolExecutor:
  • 定时任务线程池类,用于实现定时任务相关功能
  • 讲任务包装成定时任务,并按照定时策略来执行
7、ForkJoinPool:
  • 新型线程池类,Java7中新增的线程池类,基于工作窃取理论实现,运用于大任务拆小任务、任务无限多的场景;
  • 与Go中的线程模型特别雷士,都是基于工作窃取理论实现,特别适合处理归并排序这种先分后合的场景
8、Executors:
  • 线程池工具类,定义了一些快速实现线程池方法
  • 定义了一系列快速实现线程池的方法-------newXXX();不过阿里手册不建议使用这个类来新建线程池
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值