• 46-54 线程常见考点


    一、线程的两种实现方式:继承Thread类和实现Runnable接口

    二、同步的两种实现方式:synchronized,wait和notify

    三、为何不推荐使用stop()和suspend()?(参考jdk api)

    1、stop():直接终止线程  

      反对使用stop(),是因为它固有的不安全性,会导致对象处于不一致状态。

      用stop()来终止线程时,立即释放所有它锁住对象上的锁。如果这些对象处于不一致的状态,那么这些处于不一致状态的对象将对其他线程可见。

      假如一个方法在将钱从一个账户转移到另一个账户的过程中,在取款之后存款之前就停止了,锁也被释放了,那么现在银行对象就被破坏了。

      当线程想终止另一个线程的时候,它无法知道何时调用stop是安全的,何时会导致对象被破坏。所以这个方法被弃用了。

      解决:线程应在合适的时候被中断,而不应被盲目地停止。

    2、suspend():挂起线程直到另一个线程调用resume()

      反对使用suspend()方法,因为它固有的死锁倾向。

      用suspend()挂起线程时,目标线程会停下来,但却仍然持有在这之前获得的锁定。在目标线程恢复运行之前,其他任何线程都不能访问锁定资源。

      对于其他任何线程,如果它们想恢复目标线程,又想在调用resume之前锁定该挂起线程锁定的任一资源,则会发生死锁。所以这个方法被弃用了。

      解决:所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用 wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。

    四、sleep和wait区别,结合例子说明

    sleep和wait都抛出InterruptedException

    1、sleep()——Thread类的static方法,不释放锁。只是让出cpu

      作用是使此线程暂停执行,将执行机会给其他线程,在指定时间后自动恢复执行,但暂停执行时不释放锁。

      sleep作用:正在执行的线程主动让出cpu给其他线程,sleep指定的时间后cpu才回到这个线程上继续执行。如果当前线程进入了同步锁,sleep方法不释放锁。也就是说,即使当前线程使用sleep让出cpu,其他被同步锁挡住的线程依然无法执行。

    2、wait()——Object类的final方法,释放锁。需要notify()/notifyAll()唤醒它

      对一个对象调用wait方法作用是,使本线程释放对象锁并进入等待此对象的等待锁定池。只有针对此对象调用notify/notifyAll方法后本线程才进入对象锁定池准备获得对象锁进入运行状态。

      注意:调用wait时必须锁定该对象,即在synchronized中调用wait和notify/notifyAll

      wait作用:在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify/notifyAll,调用wait方法的线程才会解除wait状态,之后等到程序再次得到锁后才可继续运行。

    3、notify()/notifyAll()——Object类的final方法,不释放锁。

      notify/notifyAll不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争但不能马上得到锁,因为锁还没有被别人释放,需要执行完notify/notifyAll后面的代码后才释放锁。

      notify()唤醒一个处于等待状态的线程,但不能指定唤醒哪个线程,而是由JVM决定,也不是按照优先级;notifyAll()唤醒所有处于等待状态的线程,让它们竞争对象的锁。唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

      notify/notifyAll方法只应由作为此对象监视器的所有者的线程(即持有此对象锁的线程)来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者:

    • 通过执行此对象的同步实例方法。
    • 通过执行在此对象上进行同步的 synchronized 语句的正文。
    • 对于 Class 类型的对象,可以通过执行该类的同步静态方法。 

    五、同步和异步的区别

    1、同步

      如果数据将在线程间共享。如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须同步存取。

    2、异步

      当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步往往更有效率。

    六、当一个线程进入一个对象的一个synchronized方法后,其他线程是否可以进入该对象的其他方法?

    依据:方法是synchronized方法?是否有wait?是否static?

    1、其他方法不是synchronized方法,则可以进入。

    2、如果这个synchronized方法内部调用了wait,则可以进入其他synchronized方法。

    3、如果这个synchronized方法内部没有调用wait,则不可进入其他synchronized方法。

    4、static方法与非static方法不能同步。如果其他方法是static方法,则同步锁是当前类的字节码,而非static方法同步锁是this。

    补充:synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问改实例synchronized保护快,而static synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了,也就是synchronized相当于 this.synchronized,而
    static synchronized相当于Something.synchronized.

    七、java线程:概念与原理

    1、操作系统中线程和进程的概念

      现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。 
      进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程(至少一个线程)。比如在Windows系统中,一个运行的exe就是一个进程。  
      线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。  “同时”执行是人的感觉,在线程之间实际上轮换执行。 

    2、Java中的线程

      在Java中,“线程”指两件不同的事情: 1、java.lang.Thread类的一个实例; 2、线程的执行。   
      使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。  
      一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。  
      Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。  一个Java应用总是从main()方法开始运行,main()方法运行在一个线程内,它被称为主线程。  一旦创建一个新的线程,就产生一个新的调用栈。  线程总体分两类:用户线程和守候线程。 

    八、线程的基本状态之间的关系

      线程状态总的可分为五大状态:分别是生、死、可运行(就绪)、运行、等待/阻塞/睡眠。用一个图来描述如下(只有一处双向箭头):  

    1、新状态:线程对象已经创建,还没有在其上调用start()方法。  
    2、可运行状态(就绪状态):当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。  
    3、运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。  
    4、等待/阻塞/睡眠状态:这是线程有资格运行时它所处的状态。实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。  
    5、死亡态:当线程的run()方法完成时就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

    九、synchronized和java.util.concurrent.locks.Lock异同。

  • 相关阅读:
    bootstrap 网格系统学习
    在asp.net web api中利用过滤器设置输出缓存
    解决在开发环境中访问json配置文件时报HTTP 错误 404.3
    Newtonsoft.Json序列化和反序列
    装饰者模式学习
    SQL server跨库查询
    python-安装xlrd xlwt 插件
    vim 实际行跟屏幕行移动命令
    vim-缓存区中打开另外一个文件的方法
    vim 计算器寄存器使用
  • 原文地址:https://www.cnblogs.com/seven7seven/p/3937039.html
Copyright © 2020-2023  润新知