• 二十四 java 多线程一些知识点


    1:blocked线程和waiting的线程的区别? 如何唤醒?

       java线程中含有waiting与blocked两种状态:

       线程的 blocked状态往往是无法进入同步方法/代码块来完成的(BLOCKED是指线程正在等待获取锁)。这是因为无法获取到与同步方法/代码块相关联的锁。

      WAITING是指线程正在等待其他线程发来的通知(notify),收到通知后,可能会顺序向后执行(RUNNABLE),也可能会再次获取锁,进而被阻塞住(BLOCKED)。(有几种情况导致WAITING状态呢?: 自己call  join(),  wait(), 或等待其他线程call  notify(), notifyall())

      notify是将某个waiting的线程状态改变为blocked(由于notify的线程尚未退出临界区,尚未释放锁,所以被唤醒的线程状态变为blocked),notifyAll是将所有线程的状态改变为blocked。

            JAVA为提供了wait()和notifyAll以及notify()实现挂起线程,并且唤醒另外一个等待的线程。(这些方法只能在一个同步语句或者同步方法内调用,原因是因为如果一个方法不要求互斥,那么就没有必要在线程间监听或者是合作,每个线程都可以自由访问这个方法。)

      在JAVA虚拟机中,每个对象(Object和class)通过某种逻辑关联监视器,为了实现监视器的互斥功能,每个对象(Object和class)都关联着一个锁(有时也叫“互斥量”),这个锁在操作系统书籍中称为“信号量”,互斥(“mutex “)是一个二进制的信号量。

      我们知道JAVA每个对象(Object/class) 都关联一个监视器,更好的说法应该是每个对象(Object/class)都有一个监视器,对象可以有它自己的临界区,并且能够监视线程序列为了使线程协作,JAVA为提供了wait()和notifyAll以及notify()实现挂起线程,并且唤醒另外一个等待的线程。

      在java虚拟机中,每个对象和类在逻辑上都和一个监听器相关联。为了实现监听器的共同执行能力,锁(有时候又叫互斥量)关联着每个对象和类,在操作系统书上被称之为“信号量”,互斥量其实就是一个二态的信号量。

    3: 原子类和synchronized 哪个快?

          就算没有竞争,synchronized也比原子操作慢。

      Synchronized锁是独占的,意味着如果有别的线程在执行,当前线程只能是等待!

      比较并交换(compare and swap, CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预知性产生的数据不一致问题。 该操作通过将内存中的值与指定数据进行比较,当数值一样时将内存中的数据替换为新的值。

      它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。 这是作为单个原子操作完成的。 原子性保证新值基于最新信息计算; 如果该值在同一时间被另一个线程更新,则写入将失败。 操作结果必须说明是否进行替换; 这可以通过一个简单的布尔响应(这个变体通常称为比较和设置),或通过返回从内存位置读取的值来完成(摘自维基本科)

    CAS包含3个参数:

      V表示要更新的变量

      E表示预期值

      N表示新值

           如果V值等于E值,则将V的值设为N。若V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。通俗的理解就是CAS操作需要我们提供一个期望值,当期望值与当前线程的变量值相同时,说明还没线程修改该值,当前线程可以进行修改,也就是执行CAS操作,但如果期望值与当前线程不符,则说明该值已被其他线程修改,此时不执行更新操作,但可以选择重新读取该变量再尝试再次修改该变量,也可以放弃操作,原

    4 java  lock底层实现

    5 多线程包

    7 lock synchronized 

    8 同步方法 VS 同步代码块:

      java中,每一个对象都有一把锁,线程用synchronized获取对象上的锁。

      非静态同步方法:锁是类的对象的锁

      静态同步方法:锁的是类本身

      同步方法块:锁是可以选择的。所以能更加精确的控制。粒度更细致,可以更精确的控制对象锁。

    9 确保N个线程可以访问N个资源而不死锁?

      指定资源获取顺序。所有线程都按照同样的顺序请求资源。

    10 创建线程的方法:

      继承Thread

      实现Runnable接口:这种方式更受欢迎,因为可以继承其他的类。

      Executor框架创建线程池

    11 线程的几种可用状态:

      new:刚创建的线程,但是没有调用start。

      就绪(Runnable):调用start, run()方法就执行,但是不一定马上执行。等待时间片。

      运行(Running) :得到CPU可以执行,正在执行。

      阻塞(waitting):正在运行到线程,暂时让出CPU。各种原因可以导致阻塞:

                  sleep():调用一个在I/O上被阻塞的操作,即该操作在输入/输出完成前不会返回到调用者。

                  等待锁。Join() 也可以导致当前线程blocked。

                                 进入临界区,等待锁(synchronized,  wait,  interruped )

      死亡:run() 方法正常退出,自然死亡。未捕获到异常终止了run方法而使线程猝死。

    12 Thread类最佳实践

      写的时候最好要设置线程名称 Thread.name,并设置线程组 ThreadGroup,目的是方便管理。在出现问题的时候,打印线程栈 (jstack -pid) 一眼就可以看出是哪个线程出的问题,这个线程是干什么的。

  • 相关阅读:
    Python抓取妹子图,内含福利
    我是如何通过一部动漫学习英语的?
    SqlServer,Oracle,db2,MySql查询表索引
    cmd命令大全
    资源推荐:PPT快闪资源合集附配套字体下载
    安卓抖音全球地区版
    tomcat的Server.xml详解和Host的配置
    Java总结篇系列:Java多线程(三)
    Java总结篇系列:Java多线程(二)
    Java总结篇系列:Java多线程(一)
  • 原文地址:https://www.cnblogs.com/liufei1983/p/10925083.html
Copyright © 2020-2023  润新知