zoukankan      html  css  js  c++  java
  • 多线程

    一、定义

    进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
    
    线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
    

      

    二、分类

    守护线程:守护线程则是用来服务用户线程的,如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去。
    用户线程:Java虚拟机在它所有非守护线程已经离开后自动离开。
    举个例子:就像天上人间的保安 (守护线程),里面有牌位姑娘(非守护线程),他们是可以同时干着各自的活儿,但是 姑娘们要是都被JC带走了,那么门口的保安也就没有存在的意义了。

     

    三、多线程实现方式

    Java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。
    

    1、继承Thread类

    继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。

    2、实现Runnable接口

    如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口。
    为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例,事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run()

    3、带返回结果的多线程

    可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。
    

      

    四、New Thread() 的弊端

    执行一个异步任务,如果只是单独的new Thread(),那弊端会有如下:
    a. 每次new Thread新建对象性能差。
    b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
    c. 缺乏更多功能,如定时执行、定期执行、线程中断。
    相比new Thread,Java提供的四种线程池的好处在于:
    a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
    b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
    c. 提供定时执行、定期执行、单线程、并发数控制等功能。
    

     

    五、线程池

    Java通过Executors提供四种线程池,分别为:
    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
    1. newSingleThreadExecutor
    
    创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
    
    2.newFixedThreadPool
    
    创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
    
    3. newCachedThreadPool
    
    创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
    
    那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
    
    4.newScheduledThreadPool
    
    创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
    

      

    六、线程池的作用

    线程池作用就是限制系统中执行线程的数量。
         根 据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排 队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池 中有等待的工作线程,就可以开始运行了;否则进入等待队列。
    

     

    七、为什么用线程池

    1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
    
    2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
    

      

  • 相关阅读:
    团队项目推荐:附近商家无地图导航——by Manni
    团队项目推荐:基于社交网络的自动音乐推荐系统——by ZhongXia
    往届项目回顾:自动字幕对轴软件Autosub
    【Daily Scrum】11-19
    【Review】Review of Sprint 1& Sprint 2 planning
    【Daily Scrum】11-17 Summary of Sprint 1
    【Daily Scrum】11-13
    【Daily Scrum】11-12
    【Daily Scrum】11-11
    【Daily Scrum】11-7
  • 原文地址:https://www.cnblogs.com/binbang/p/5431278.html
Copyright © 2011-2022 走看看