目录

并发编程面试题二

目录

并发编程面试题二

1、java线程常见的基本状态有哪些,这些状态分别是做什么的

(1)创建(New):new Thread(),生成线程对象。

(2)就绪(Runnable):当调用线程对象的star()方法,线程就会进入就绪状态,但此刻线程调度还没把该线程设置为当前线程,就是还没有获得CPU使用权。如果线程从睡眠或等待回来之后,也会进入就绪状态。

(3)运行(Running):程序将处于就绪状态的线程设置为当前线程,即获得CPU使用权,这个时候线程进入运行状态,开始运行run里面的逻辑。

(4)阻塞(Blocked):分为等待阻塞跟同步阻塞

等待阻塞:调用wait(状态就会变成WAITING状态),或调用sleep(状态就会变成TIMED_WAITING),调用join或发出IO请求。进入该状态的线程需要等待其他线程做出一定的动作(通知或中断),处于这种状态的线程CPU不会分配过来,它们需要被唤醒,也可能会无限等待下去,阻塞结束后线程重新进入就绪状态。

同步阻塞:线程在获取synchronized同步锁失败,即锁被其他线程占用,它就会进入同步阻塞状态。

(5)死亡(TERMINATED):一个线程run方法执行结束,该线程就死亡了,不能进入就绪状态。

注意:有些文档把就绪和运行两种状态统一称为 “运行中”。

等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。

2、多线程开发里面常用的方法有哪些,分别解释下

(1)sleep

属于线程Thread的方法

让线程暂缓执行,等待预计时间之后再恢复

交出CPU使用权,不会释放锁

进入阻塞状态TIMED_WAITING,睡眠结束则变为Runnable

(2)yield

属于线程Thread的方法

暂停当前线程的对象,去执行其他线程

交出交出CPU使用权,不会释放锁

不会让线程进入阻塞状态,直接变为就绪Runnable,只需要重新获得CPU使用权

作用:让相同优先级的线程轮流执行,但是不保证一定轮流

(3)join

属于线程Thread的方法

在主线程上运行调用该方法,会让主线程休眠,不会释放已经持有的对象锁

让调用join方法的线程先执行完毕,在执行其他线程

(4)wait

属于Object的方法

当前线程调用对象的wait方法,会释放锁,进入线程的等待队列

需要依靠notify或者notifyAll唤醒,或者wait(timeout)时间自动唤醒

(5)notify

属于Object的方法

唤醒在对象监视器上等待的单个线程,选择是任意的

(6)notifyAll

属于Object的方法

唤醒在对象监视器上等待的全部线程

3、画出线程的状态转换图和这些转换过程常用的api

https://i-blog.csdnimg.cn/direct/181d45a0ffc546dcb1c79481a9c58312.png

4、哪些不是线程安全的数据结构(哪些是线程安全的数据结构)

ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap。

(Vector、 Hashtable )

5、Java中可以有哪些方法来保证线程安全

  • 加锁,比如synchronize/ReentrantLock
  • 使用volatile声明变量,轻量级同步,不能保证原子性(需要解释)
  • 使用线程安全类(原子类AtomicXXX,并发容器,同步容器 CopyOnWriteArrayList/ConcurrentHashMap等
  • ThreadLocal本地私有变量/信号量Semaphore等

6、解释一下volatile关键字,还有它跟synchronized有什么区别

volatile是轻量级的synchronized,保证了共享变量的可见性,被volatile关键字修饰的变量,如果值发生了变化,其他线程立刻可见,避免出现脏读的现象。

区别:volatile保证可见性,但是不能保证可见性。

synchronized保证可见性,也保证可见性。

7、为什么会出现脏读

JAVA内存模型简称 JMM,JMM规定所有的变量存在主内存,每个线程都有自己的工作内存,线程对变量的操作都在工作内存进行,不能直接对主内存进行。

volatile关键字修饰的变量是随时可以看到自己最新的值,假如线程1对变量v进行修改,那么线程2是可以马上看见。

使用volatile修饰变量的话,每次读取前必须从主内存属性最新的值,每次写入需要立刻写到主内存中。

8、解释下什么是指令重排

指令重排序分两类 编译器重排序和运行时重排序。JVM在编译java代码或者CPU执行JVM字节码时,对现有的指令进行重新排序,主要目的是优化运行效率(不改变程序结果的前提)。

9、解释下happens-before

先行发生原则,volatile的内存可见性就提现了该原则之一。