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

    http://www.mamicode.com/info-detail-517008.html

    进程和线程:

    • 进程:执行中的程序(狭义),一个具有独立功能的程序关于某个数据集合的一次运行活动(广义),每个进程都有独立的代码和数据空间(进程上下文),进程是系统进行资源分配和调度的一个独立单位,进程间的切换开销较大,一个进程包含1--n个线程
    • 线程:线程是进程的一个实体,是CPU调度和分配的基本单位,与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行顺序,线程切换开销小

    并发、并行、同步、异步:

    • 并发:在操作系统中,同一个处理机上,一个时间段内有几个程序都处于启动运行到运行完毕之间(但在某个时间点,只有一个程序在执行)
    • 并行:针对多处理器而言,在某一时刻,有多条任务在执行
    • 同步:顺序执行,执行完一个再执行下一个,需要等待,协调运行
    • 异步:彼此独立,在等待某个事件的过程中继续做自己的事

    多线程的目的是更好的使用CPU的资源

    1、进程的三种状态

    • 就绪状态:进程获得除CPU以外的所有资源,只要获得处理机便可执行
    • 执行状态:进程获得处理机,正在处理机上执行
    • 阻塞状态:进程等待某种事件发生(如等待I/O完成),放弃处理机而处于阻塞状态

    2、线程的基本状态

    1. 新建
      new 创建了一个线程对象,分配了内存
    2. 等待
      new之后,start()之前
    3. 就绪
      star()之后,位于CPU的可运行线程池中,等待CPU调度
    4. 运行
      获得CPU执行权,正在执行run()方法,任何时刻只会有一个线程处于运行状态,只有就绪状态中的线程才有机会进入运行状态
    5. 阻塞
      • 等待阻塞:运行的线程调用wait()方法,JVM把线程放入等待池中,只有收到notify()或者notifyAll()消息,才会进入就绪状态(可运行)
      • 同步阻塞:运行的线程在获取对象的同步锁时,该同步锁被其他线程占用,JVM会把这个线程放入锁池
      • 其他阻塞:运行的线程调用sleep()方法,或者发出I/O请求,当sleep()超时或者I/O完成,线程就重新进入就绪状态
    6. 死亡
      执行完run()

    3、创建线程的三种方式

    参考资料:[http://blog.csdn.net/longshengguoji/article/details/41126119]

    1. 继承Thread类,重写run
    2. 实现Runable接口,实现run,实现类的实例作为Thread类的参数传入
    3. 通过Callable接口和Future接口
      • 创建Callable实现类,实现call方法
      • 创建该实现类的对象,并用FutureTask类来包装该对象
      • FutureTask对象作为Thread的参数 创建线程
      • 调用FutureTask的get()获得子线程执行后的返回值

      对比:

      

    采用实现Runnable、Callable接口的方式创见多线程时,优势是:

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

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

    劣势是:

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

    使用继承Thread类的方式创建多线程时优势是:

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

    劣势是:

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

    4、线程状态转换和常用方法

    • join()
      强行执行线程   t.join()
    • sleep()
      让线程休眠(暂停执行)
      是线程在指定时间内阻塞,指定时间一过重新进入就绪状态
    • wait()和notify()
      • wait(xxx)  当对应的notify()被调用或者超出指定时间,线程就会进入就绪状态
      • wait()  只有当对应的notify()被调用 才会进入就绪状态
    • suspend()和resume()
      suspend()使线程进入阻塞状态并且不会自动恢复。只有当对应的resume()被调用才会进入就绪状态
    • yield()
      线程礼让
      使线程放弃当前获得的CPU时间,但是不进入阻塞,线程任处于就绪状态,随时可以再获得CPU执行
    • sleep()和wait区别
      • sleep():Thread中;线程暂停执行指定时间,到时自动进入可运行状态,不会释放对象锁
      • wait():Object中;线程释放对象锁,进入此对象的等待锁定池,只有针对次对象notify或notifyall,线程才会进入可运行状态

    wait()、notify()、notifyall()这三个方法是Object类的,而不是Thread类的,可以用来控制线程的状态

    当对象调用了wait():使持有这个对象的线程把对该对象的控制权交出去,然后进入等待状态

    当对象调用了notify()/notifyAll():通知一个/所有等待这个对象的控制权的线程参与到对象锁的竞争中

    5、线程同步、锁、死锁

      线程同步是为了防止多个线程访问同一个数据对象时 对数据造成破环

      每个对象都有(且只有)一个内置锁,当程序运行到synchronized同步代码块或同步方法时,对象锁才会起作用

      当一个线程A拥有一个对象的锁的时候,其他线程就不可以获得该锁,直到线程A释放锁(线程A退出synchronized代码块或同步方法)

           关于synchronized关键字:http://www.cnblogs.com/QQParadise/articles/5059824.html

      synchronized锁住的是代码还是对象?
      答:synchronized锁住的是括号里的对象,对于非static 的synchronized方法,锁住的是对象本身,也就是this

      当synchronized锁住一个对象后,其他线程要想获得该对象的锁就必须等线程执行完成释放锁,才能再次给对象加锁

      所以在使用synchronized的时候,能缩小代码段的范围就尽量缩小,能在代码块上加同步就不在整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发,原因就是如果锁住的代码段太长,别的线程就要等很久,等得花儿都谢了

      非static的synchronized和static synchronized

    • 前者是实例锁(如果该类是单例,那么也相当于全局锁),后者是全局锁(无论实例有多少个,线程都共享该锁)
    • static synchronized方法,方法中无法使用this,所以它锁的不是this 而是类的class对象
    • synchronized(类名.class)  也可以实现全局锁

        

      

  • 相关阅读:
    vs中添加wsdl生成代理类工具
    vscode+prettier 设置保存自动格式化
    k8s 部署项目
    Jmate使用
    k8s部署项目
    docker 打包镜像 部署项目
    vs2012编译xp运行的mfc程序InitializeCriticalSectionEx解决方案
    thinkphp 入口文件 iis 500错误
    java初学之stream
    php preg_match正则长度限制
  • 原文地址:https://www.cnblogs.com/gucl/p/8030648.html
Copyright © 2011-2022 走看看