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

    1.什么进程?
    * 值得就是正在运行的程序,是系统进行资源分配和调用的独立单位
    * 每一个进程都有它自己的内存空间和系统资源

    特征:

    1、独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间

    2、动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念。进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的

    3、并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。

    2.什么线程?
    * 是进程中的每个顺序控制流,是一条执行路径
    * 一个进行如果只有一条执行流程,则为单线程
    * 一个进程有多条执行路径,则为多线程(多线程优点:

    1、进程之间不能共享内存,但线程之间共享内存非常容易。

    2、系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发比多进程的效率高

    3、Java语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了Java的多线程编程)

    * 3.什么是并行?什么是并发?
    * 前者是逻辑上同时发生,指在某一个时间内同时运行的多个程序
    * 后者是物理上同时发生,指在某一个时间内同时运行多个程序
    * 4.java的运行原理?
    * 由java命令启动JVM,JVM启动就相当于启动了一个进程
    * 接着该进程创建了一个主线程去调用main()方法
    * 5.需求:我们要实现多线程的一个程序,问 我们要如何进行实现?
    * 由于线程是依赖进程而 存在的,所以我们应该先创建一个进程出来,
    * 而进程是由系统进行创建的,所以我们应该去调用系统工程,创建一个进程
    * java是不能直接去调用系统功能的,所以我们没办法直接实现多线程的程序
    * 但是呢,java可以去调用C/C++写好的程序来实现多线程的
    由C/C++去调用系统功能创建进程,然后由java去调用这个方法

    1.继承Thread类
    步骤:
    1.自定义MyThread,继承Thread类
    2.在MyThread中重写run()方法(该run方法的方法体就代表了线程需要执行的任务)
    为什么要重写run()方法?
    不是类中的所有代码都需要被线程去执行的.
    而这个时候呢,为了区分哪些代码能够被线程执行。java中提供了Thread类中的run()
    用来包含哪些被线程执行的代码
    3.创建对象(创建Thread类的实例)
    4.启动线程(调用线程的start()方法来启动线程 )

    run() 他是一个单线程,直接可以当做普通方法去使用,
    如果我想 执行一个多线程 那么另一个方法 start()

    线程的生命周期:

    新建和就绪状态:

    当程序使用new关键字创建一个线程后,该线程就处于新建状态。

    当线程对象调用了start()方法后,该线程就处于就绪状态。

    运行和阻塞状态:

    如果处于就绪状态的线程获取了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。

    当线程调用sleep(),调用一个阻塞式IO方法,线程会被阻塞

    死亡状态:

    1、run()或者call()方法执行完成,线程正常结束

    2、线程抛出一个未捕获的Exception或Error

    3、直接调用该线程的stop方法来结束该线程——该方法容易导致死锁,不推荐使用

     创建线程的三种方法:

    采用Runnable、Callable接口的方式创建多线程的优缺点:

    优点:

    1、线程类只是实现了 Runnable接口或 Callable接口,还可以继承其他类

    2、在这种方式下,多个线程可以共享同一个 target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

    缺点:

    编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法。

    采用继承 Thread类的方式创建多线程的优缺点:

    优点:

    编写简单,如果需要访问当前线程,则无须使用 Thread.current Thread()方法,直接使用this即可获得当前线程

    缺点:

    因为线程已经继承了Thread类,所以不能再继承其他类

    start()和run的区别?

    run()仅仅是封装线程执行的代码,直接调用时可以是 一个普通的方法
    start()首先启动了进程,然后由jvm去调用该线程的run()方法

    // Thread t = new Thread();
    // t.start();
    // t.start();
    //报错:java.lang.IllegalThreadStateException 非法的线程状态异常
    //为什么会产生这个错误
    // 是这个相当于t线程被调用了两次,而不是两个线程启动

    虽然这个线程被调用了两次,可是呢 我还不知道到底是哪个线程去执行的,
    获取和设置线程的名称

    Thread类的基本获取和设置线程的方法:

    1.public final String getName() 获取线程的对象名称
    2.public final void setName(String name):设置线程的名称
    我们也可以通过构造方法去给线程起名称
    问:

    如果获取了main方法所在的线程名称?
    例如:针对如果不是Thread类的子类中如何获取线程名称对象呢?
    1public static Thread curretThread() 返回当前正在执行的线程名称
    2.Thread.curretThread().getName()

    我们要获取main()方法 所在的线程对象名称  如何解决?

    //遇到这种情况呢,Thread类提供了一个很好玩的方法
    1.public static Thread currentThread() 返回当前正在执行的线程对象

    线程的调度
    假如我们的计算机只有一个cpu,那么CPU在某一个时刻只能执行一条指令
    线程只有得到CPU时间片才能有使用权,才能执行指令
    线程的两种调度策略
    1.分时调度策略: 所有线程轮流的去使用CPU的使用权,平均进行分配,每个线程占用CPU的时间
    2.抢占式调度策略:优先让级别高的线程使用CPU,如果线程的优先级相同,那么他们会随机选择一个,优先级高的线程获取CPU
    时间片的调度策略会多一些.
    注意:java中用的就是抢占式调度模型

    我们的线程是没有设置优先级的,肯定是有默认的优先级

    在java中默认的优先级是5
    线程优先级的范围:1-10
    线程优先级仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看见更好的效果

    设置线程优先级的方法?

    public final  void serPRriority(int NewPriority) : 更改线程对的优先级

    线程的睡眠:

    方法:
    public static void sleep(long milis):在指定的毫秒数内让当前正在执行的线程休眠(暂停一会再去执行)
    注意:
    在sleep中 传入值是毫秒值

    线程的加入:

    方法:
    1.public final void join():等待该线程或者终止
    大体的概念:
    我调用了这个方法,必须线程执行完毕之后,其他的线程才能调用

    线程的中断与结束:

    方法:
    public final stop():让线程停止,过时间了,但是还可以使用
    public void interrupt():中断线程,把线程装填停止,并抛出一个INTERRUPTEDEXCEPTION

    创建线程的另一种方法  :

    Runnable接口的类,该类也会去实现run()方法,然后可以分配该类的实例,
    实现Runnable接口的好处:
    1.可以避免由于JAVA当继承带来的局限性
    2.适合多个相同的程序的代码去处理同一个资源的问题,把线程同程序的代码、数据有效的进行分离,较好的体现了面向对象的设计思想

    实现Runable接口的步骤

    1.定义一个MyRunnable,实现Runable接口
    2.在MyRunnable中重写run()方法
    3.创建MyRunnable类的对象
    4.创建Thread类的对象,把MyRunnable对象作为构造方法的参数
    5.启动线程

    使用Runnable接口的好处:不影响MyRunnable继承其他的类

    同步锁的弊端

    1.效率比较低
    2.容易产生死锁

    例如:
    两个或者两个以上的线程在争夺资源的过程中,发生了一种互相等待的现象

    (举例:

    中国人、美国人吃饭案例
    正常情况下: 中国人:一双筷子

    美国人:一个刀一个叉

    现在的问题:
    中国人:一只筷子 一个刀
    美国人:一只筷子 一个叉

    线程之间的通信:

    针对同一个资源的操作有不同种类的类型
    只出不进:电影院卖票(八佰、金刚川)
    可进可出:早餐店(生产者:厨师 消费者:顾客)

    Lock锁

    背景 :
    虽然我们可以理解同步代码块和同步方法的所对象,但是我们并没有看见那块上了锁,并在哪里释放了锁
    为了更好更清晰的表达如何并如何释放锁,JDK5之后提供了一个新的锁对象,LOCK
    lock是接口不能直接序列化,这里采用他的实现类ReentrantLock来实例化
    方法ReentrantLock创建一个ReentrantLock的实例
    加锁解锁的方法:
    方法名 说明
    void lock() 获得锁
    void unlock() 释放锁

    线程池

    线程池的基本背景
    程序启动一个新的线程成本是很高的,因为它涉及到与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是
    当程序中要创建大量的生存很短的线程时,就要考虑使用线程池
    线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中称为空闲状态,等待下一个对象来使用
    java内置支持线程池
    线程是使用进程的资源,所以每次开启一个线程,它的成本是比较高的,所以使用线程池,就能解决这个问题
    如何使用线程池?
    Executors工厂来产生线程池,如一下几个方法
    1.public static ExecutorService newCachedThreadPool()开启具有缓存功能的线程池
    2.public static ExecutorService newFixedThreadPool(int nThreads) 创建爱你多少个线程池
    3.public static ExecutorService newSingleThreadExecutor()创建单个的线程池

    这些方法的返回值是ExecutorService对象,该对象表示一个线程池..可以执行Runnable对象或者Callable对象代表的线程.

    步骤:

    1.创建线程池对象
    2.创建Runnable实例
    3.提交Runnable实例
    4..关闭线程池

    线程池的好处

    线程池里面的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲装填,等待下一个对象来使用

    实现Callable接口

    好处:

    1.可以有返回值
    2.可以抛出异常

    弊端:

    代码比较复杂,所以一般不用

  • 相关阅读:
    P4549 【模板】裴蜀定理
    POJ1606 Jugs
    2. 数据库连接池规范
    14. BootStrap * 组件
    BootStarpt
    13. Flex 弹性布局2 BootStrap
    12. Flex 弹性布局 BootStrap
    CSS3
    21. Servlet3.0 / 3.1 文件上传 Plus
    20. Servlet3.0 新特性
  • 原文地址:https://www.cnblogs.com/mrr19990327/p/14204885.html
Copyright © 2011-2022 走看看