zoukankan      html  css  js  c++  java
  • JAVA基础知识总结:十八

    一、进程和线程
    1.进程
    是一个程序的运行状态和资源占用的描述

    进程的特点:
    a.独立性:不同的进程之间是独立的,相互之间资源不共享
    b.动态性:进程在系统中不是静止不动的,而是一直活动的
    c.并发性:多个进程可以在同一个处理器上同时进行,互不影响

    多进程:一个操作系统可以运行多个应用程序

    2.线程
    线程是进程的组成部分,一个进程可以有多个线程,每个线程用来处理一个指定的子任务

    举例:打开酷狗软件-------》这是一个进程
    播放歌曲/刷新歌词------》两个线程(并发的)

    线程的执行是抢占式的,多个线程可以在一个进程中并发执行,其实质是CPU在不同的线程之间进行快速的切换,也就是说,当前运行的线程在任何时候都有可能被挂起,以便于别的线程去执行对应的任务,同样的,被挂起的线程随时有可能争抢到时间片,继续执行

    多线程:在一个进程中,多个线程同时进行
    应用:一个浏览器可以同时下载多张图片
    一个服务器可以同时响应多个用户请求


    3.进程和线程之间的关系
    a.一个程序运行后至少有一个进程
    b.一个进程可以包含多个线程,但至少需要有一个线程,否则进程是没有意义的

    为什么要选用多线程编程而不选用多进程呢?/线程相对于进程的优点?
    a.进程间资源不能进行共享,但是线程之间可以共享资源
    b.系统如果要创建进程的话,需要为这个进程重新分配系统资源,而创建线程的话则相对容易的多,因此使用线程处理并发任务比进程的效率高
    c.Java中内置了多线程的功能支持,简化了多线程编程


    二、线程的实现
    1.继承自Thread类
    Thread类是所有线程类的父类,实现了对线程的抽取和封装
    1>使用Thread类创建并开启线程的步骤:
    a.定义一个类,继承自Thread类,重写该类的run方法,该run方法的方法体就代表了线程需要完成的任务,因此,run方法体也被称为线程执行体
    b.创建子类的对象,即相当于创建了一个线程
    c.需要使用start方法手动开启线程


    关于线程的执行,需要注意的问题:
    a.如果一个线程中的所有的任务都处理完了,那么这个线程会自动停止(正常情况)
    b.如果在一个线程a中开辟了子线程a0,a1,a2.....那么线程a停止后,在这个线程中开辟的子线程会全部停止
    c.多个线程并发执行,其实就是在争抢CPU时间片


    2.实现接口Runnable
    使用实现Runnable接口的方式创建并开启线程的步骤:
    a.定义一个类,这个类实现Runnable接口,需要重写对应的run方法,run方法的方法体同样是线程的执行体
    b.创建实现了Runnable接口对应类的对象,并以此实例作为Thread类的target对象
    c.手动调用start方法开启线程

    两种方式实现线程的比较:
    1.实现Runnabel接口
    a.自定义的类只是实现了Runnable接口,同时还可以去继承其他的类
    b.多个线程可以共享同一个target对象,所以非常适合多个相同的线程来处理同一份资源的情况
    弊端:不直观,如果要获取当前正在运行的线程,只能通过Thread.currentThread()
    2.继承Thread类
    直观,如果要访问正在运行的线程,除了可以通过Thread.currentThread()方式之外,还可以使用super关键字

    弊端:因为线程类已经继承了Thread类,所以不能再去继承其他的类(单继承)


    实际上,大多数的多线程应用都采用实现Runnable接口的方式实现(推荐使用匿名内部类)


    三、线程的生命周期
    对象的生命周期:从一个对象被实例化到这个对象被销毁的过程中,这个对象经历的种种状态

    举例:人的生命周期:出生---婴儿---儿童---少年---青年----中年---老年---死亡


    对于线程,当一个线程被创建并启动之后,它既不是一启动就进入了执行状态,也不是一直处于执行状态,在线程的生命周期中,同样的也会经历各种过程(在一个进程中,多个线程可以并发,争抢CPU时间片)


    New(新生):线程被实例化,但是还没有开始执行
    Runnable(就绪):没有争抢到时间片
    Running(运行):争抢到了时间片,开始执行线程中的任务
    Blocked(阻塞):线程再执行的过程中遇到突发状况,使得其他的线程争抢去了时间片,被阻塞的线程会等待合适的时机重新进入就绪状态
    Dead(死亡):线程终止
    a.run方法执行完毕,线程正常结束
    b.直接调用该线程的stop方法强制终止这个线程(这种做法比较危险,死锁)

    四、线程的常用方法
    1.设置线程的优先级
    可以通过设置优先级来改变线程抢到时间片的概率,优先级高的线程抢到时间片的概率比较高,可以获得更多的执行机会

    默认情况下,每个线程的优先级都与创建它的的父线程具有相同的优先级
    setPriority(),所传的参数范围1~10,默认为5,对应的数值越大,说明优先级越高,这个方法的设置一定要在start之前

    2.使得线程休眠
    使得当前正在执行的线程休眠一段时间,释放时间片,导致线程进入阻塞状态
    sleep(5000);5000代表的是毫秒
    设置了sleep就相当于将当前线程挂起5s,这个操作跟线程的优先级无关,当对应的时间到了之后,还会再执行,
    如果只设置了优先级的话,等于给设置了优先级的线程设置冲突,那么被挂起的是优先级比较低的那个线程

    3.中断线程
    interrupt()
    interrupt只是改变一个线程的状态,并不是真正的停止一个线程
    如果线程处于阻塞状态(sleep,join),则中断状态被清除
    如果一个线程没有处于阻塞状态,这时调用interrupt将不起作用,否则,会引起InterruptedException异常(该线程预先准备好处理此状况)

    实际看到的效果:停止了线程

    在线程的执行体中,可以通过 boolean isInterrupted() 来测试线程是否已经中断。


    4.线程合并
    join()
    优先执行被合并进来的线程,执行完合并进来的线程之后,再执行原来的线程


    5.后台线程
    setDeamon()
    又被称为守护线程或者精灵线程
    特征:如果所有的前台线程都死亡,后台线程会自动死亡

    这个方法的调用需要在start之前

    6.线程让步
    yield()
    yield方法是一个和sleep方法相似的方法
    它可以让当前正在执行的线程暂停,但他不会阻塞该线程,它只是将该线程转入就绪状态,完全会出现的一个情况是:当某个线程调用了yield方法暂停之后,线程调度器可能会将该线程立马调起来进入执行状态
    实际上,只有优先级相同或者优先级更高的线程才有可能获取执行的机会

    yield方法和sleep方法的区别:
    a.sleep方法暂停当前线程之后,会给其他线程执行的机会的,但是跟线程的优先级没有关系,yield只有优先级相同或者优先级更高的线程才有可能获取执行的机会
    b.sleep会将一个线程转入阻塞状态,但是yield不会,只是做出了让步
    c.sleep会有InterruptedException的异常,但是yield没有
    d.sleep可以有更好的可移植性,通常不要依靠yield来控制并发的线程

  • 相关阅读:
    184. Department Highest Salary【leetcode】sql,join on
    181. Employees Earning More Than Their Managers【leetcode】,sql,inner join ,where
    178. Rank Scores【leetcode】,sql
    177. Nth Highest Salary【leetcode】,第n高数值,sql,limit,offset
    176. Second Highest Salary【取表中第二高的值】,sql,limit,offset
    118. Pascal's Triangle【LeetCode】,java,算法,杨辉三角
    204. Count Primes【leetcode】java,算法,质数
    202. Happy Number【leetcode】java,hashSet,算法
    41. First Missing Positive【leetcode】寻找第一个丢失的整数,java,算法
    删除
  • 原文地址:https://www.cnblogs.com/lidar/p/7743279.html
Copyright © 2011-2022 走看看