0.前言

在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分,本文汇总了常见的一些多线程面试题。

一些问题,比如volatile关键词的作用,synchronized和ReentrantLock的区别,wait()和sleep()的区别等等问题,已经在之前写过的文章中提到过了,这里就不赘述了,有兴趣可以查看以下几篇文章:Java并发——线程同步volatile与synchronized详解Java技术——Java多线程学习Java并发——synchronized和ReentrantLock的联系与区别

下面是总结的之前没有提到过的面试重点题。转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52411531

1.多线程有什么用

(1)发挥多核CPU的优势

如果是单线程的程序,那么在双核CPU上就浪费了50%,在4核CPU上就浪费了75%。多线程可以真正发挥出多核CPU的优势来,达到充分利用CPU的目的。

(2)防止阻塞

多条线程同时运行,一条线程的代码执行阻塞,也不会影响其它任务的执行。

2. Runnable接口和Callable接口的区别

Runnable接口中的run()方法的返回值是void,它只是纯粹地去执行run()方法中的代码而已;

Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。

3.  CyclicBarrier和CountDownLatch的区别

两个类都在java.util.concurrent下,都可以用来表示代码运行到某个点上,二者的区别在于:

(1)CyclicBarrier的某个线程运行到某个点上之后,该线程即停止运行,直到所有的线程都到达了这个点,所有线程才重新运行;CountDownLatch则不是,某线程运行到某个点上之后,该线程会继续运行。

(2)CyclicBarrier只能唤起一个任务,CountDownLatch可以唤起多个任务。

(3)CyclicBarrier可重用,CountDownLatch不可重用,计数值为0该CountDownLatch就不可再用了

4.  线程安全的级别

代码在多线程下执行和在单线程下执行永远都能获得一样的结果,那么代码就是线程安全的。

线程安全也是有级别之分的:

(1)不可变

像String、Integer、Long这些,都是final类型的类,任何一个线程都改变不了它们的值,要改变除非新创建一个,因此这些不可变对象不需要任何同步手段就可以直接在多线程环境下使用

(2)绝对线程安全

不管运行时环境如何,调用者都不需要额外的同步措施。Java中有绝对线程安全的类,比如CopyOnWriteArrayList、CopyOnWriteArraySet。

(3)相对线程安全

相对线程安全也就是我们通常意义上所说的线程安全,像Vector这种,add、remove方法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个Vector,同时另一个线程在add这个Vector,99%的情况下都会出现ConcurrentModificationException,也就是fail-fast机制。

(4)线程非安全

这个就没什么好说的了,ArrayList、LinkedList、HashMap等都是线程非安全的类

5.  如何在两个线程之间共享数据

通过在线程之间共享对象就可以了,然后通过wait/notify/notifyAll、await/signal/signalAll进行唤起和等待,比方说阻塞队列BlockingQueue就是为线程之间共享数据而设计的

6.为什么wait()方法和notify()/notifyAll()方法要在同步块中被调用

这是JDK强制的,wait()方法和notify()/notifyAll()方法(都是Object的方法)在调用前都必须先获得对象的锁。

7.  wait()方法和notify()/notifyAll()方法在放弃对象监视器时有什么区别

wait()方法立即释放对象监视器,notify()/notifyAll()方法则会等待线程剩余代码执行完毕才会放弃对象监视器。

8.  怎么检测一个线程是否持有对象监视器

Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候才会返回true,注意这是一个static方法,这意味着“某条线程”指的是当前线程。

9.ConcurrentHashMap的并发度是什么

ConcurrentHashMap的并发度就是segment的大小,默认为16,这意味着最多可以同时有16条线程操作ConcurrentHashMap,这也是ConcurrentHashMap对Hashtable的最大优势。

10.  ReadWriteLock是什么

不是说ReentrantLock不好,只是ReentrantLock某些时候有所局限。

如果使用ReentrantLock是为了防止线程A在写数据、线程B在读数据造成的数据不一致(读和写同时操作造成的)。那么如果线程C在读数据,线程D也在读数据,读数据是不会改变数据的,那就没有必要加锁,但是还是ReentrantLock还是加锁了,这很显然降低了程序的性能。

读写锁ReadWriteLock应运而生。ReadWriteLock是一个读写锁接口,ReentrantReadWriteLock是ReadWriteLock接口的一个具体实现,实现了读写的分离:读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提升了读写的性能。

11.  如果你提交任务时,线程池队列已满,这时会发生什么

如果你使用的LinkedBlockingQueue,也就是无界队列的话,没关系,继续添加任务到阻塞队列中等待执行,因为LinkedBlockingQueue可以近乎认为是一个无穷大的队列,可以无限存放任务;

如果你使用的是有界队列比方说ArrayBlockingQueue的话,任务首先会被添加到ArrayBlockingQueue中,ArrayBlockingQueue满了,则会使用拒绝策略。

12.  Java中用到的线程调度算法是什么

抢占式:一个线程用完CPU之后,操作系统会根据线程优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。为了让某些低优先级的线程也能获取到CPU控制权,平衡CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作。

13. 多线程中的忙循环是什么

忙循环就是程序员用循环让一个线程等待,不像传统方法wait(),sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存(在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存)。为了避免重建缓存和减少等待重建的时间就可以使用它了。

14.  什么是自旋

很多synchronized里面的代码只是一些很简单的代码,执行时间非常快,此时等待的线程都加锁可能是一种不太值得的操作,不妨让等待锁的线程不要被阻塞,而是在synchronized的边界做忙循环,这就是自旋。如果做了多次忙循环发现还没有获得锁,再阻塞,这样可能是一种更好的策略。

15.  什么是乐观锁和悲观锁

(1)乐观锁:乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-设置这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,继而执行相应的重试逻辑。

(2)悲观锁:悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized。

16.  实现一个死锁

当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形:

(1)线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2。

(2)线程A试图获取lock2,因为线程B正持有lock2,因此线程A会阻塞等待线程B对lock2释放。

(3)如果此时线程B也在试图获取lock1,同理线程也会阻塞。

(4)两者都在等待对方所持有但是双方都不释放的锁,这时便会一直阻塞形成死锁。

//存放两个资源等待被使用
public class Resource {
public static Object obj1 = new Object();
public static Object obj2 = new Object();
}
//线程1
public class DeadThread1 implements Runnable {
@Override
public void run() {
synchronized (Resource.obj1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
synchronized (Resource.obj2) {
System.out.println("DeadThread1 ");
}
}
}
}
//线程2
public class DeadThread2 implements Runnable {
@Override
public void run() {
synchronized (Resource.obj2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
synchronized (Resource.obj1) {
System.out.println("DeadThread2 ");
}
}
}
} //主函数中调用
Thread t1 = new Thread(new DeadThread1());
Thread t2 = new Thread(new DeadThread2());
//启动两个线程
t1.start();
t2.start();

17.  线程类的构造方法、静态块是被哪个线程调用的

被new这个线程类所在的线程所调用的,而run方法里面的代码才是被线程自身所调用的。

18.  锁粗化是什么意思

同步块之外的代码是异步执行的,这比同步整个方法更提升代码的效率。因此也很容易理解同步的范围越少越好的意义。但是Java虚拟机中存在着一种叫做锁粗化的优化方法,这种方法就是把同步范围变大。

比方说StringBuffer,它是一个线程安全的类,反复append字符串意味着要进行反复的加解锁,这对性能不利,因为JVM在这条线程上要反复地在内核态和用户态之间切换,因此JVM会将多次append方法调用的代码进行一个锁粗的操作,将多次的append的操作扩展到append方法的头尾,变成一个大的同步块,从而提升代码执行效率。

Java面试——多线程面试题总结的更多相关文章

  1. Java面试,面试题

    Java面试,面试题 HashMap,HashTable,ConcurrentHash的共同点和区别 HashMap HashTable ConcurrentHashMap ArrayList和Lin ...

  2. 【java】:多线程面试题

    经常面试的时候,让写各种乱七八糟的多线程面试题,收集了很多,有些还是挺好玩的. 1.编写程序实现,子线程循环10次,接着主线程循环20次,接着再子线程循环10次,主线程循环20次,如此反复,循环50次 ...

  3. Java并发多线程面试题 Top 50

    不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎.大多数待遇丰厚的Java开发职位都要求开发者精通多线程 ...

  4. java面试多线程问题

    Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环 ...

  5. java面试| 线程面试题集合

    集合的面试题就不罗列了,基本上在深入理解集合系列已覆盖 「 深入浅出 」java集合Collection和Map 「 深入浅出 」集合List 「 深入浅出 」集合Set 这里搜罗网上常用线程面试题, ...

  6. Java面试中笔试题——Java代码真题,这些题会做,笔试完全可拿下!

    大家好,我是上海尚学堂Java培训老师,以下这些Java笔试真题是上海尚学堂Java学员在找工作中笔试遇到的真题.现在分享出来,也写了参考答案,供大家学习借鉴.想要更多学习资料和视频请留言联系或者上海 ...

  7. java面试——多线程

    背景:java知识比较宽泛,最好对每一类知识点进行分类总结,方便后面学习查看.该文主要用来总结多线程方面的知识点. 并发与并行的概念 并发性(concurrency)和并行性(parallel)是两个 ...

  8. 125条常见的java面试、笔试题大汇总

    1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解所有问题,而仅仅是选择当中的一部分,临时不用部分细节.抽象包含两个方面,一是过程抽象. ...

  9. 【OD深入学习】Java多线程面试题

    一.参考文章 1. Java线程面试题 Top 50 2. Java面试——多线程面试题 3. JAVA多线程和并发基础面试问答 4. 15个顶级Java多线程面试题及回答 二.逐个解答 三.一语中的 ...

随机推荐

  1. CI框架更新与删除

    $this->load->database();        // $query=$this->db->get('t_repayments');        // $res ...

  2. git 如何生成 SSH 公钥

    1.打开你的git bash 窗口 2.进入.ssh目录:cd ~/.ssh 3.找到id_rsa.pub文件:ls 4.查看公钥:cat id_rsa.pub    或者vim id_rsa.pub ...

  3. SQL Server(第二章) 字符串函数、日期时间函数、转换函数

    --1.CONCAT 函数:字符串连接(支持sql server2012 SQL规则 如果与NULL连接返回NILL) SELECT empid,CONCAT(firstname,lastname) ...

  4. LeetCode OJ Container With Most Water 容器的最大装水量

    题意:在坐标轴的x轴上的0,1,2,3,4....n处有n+1块木板,长度不一,任两块加上x轴即可构成一个容器,其装水面积为两板的间距与较短板长之积,以vector容器给出一系列值,分别代表在0,1, ...

  5. IOS Modal(切换另外控件器方式)

    ● 除了push之外,还有另外一种控制器的切换方式,那就是Modal ● 任何控制器都能通过Modal的形式展示出来 ● Modal的默认效果:新控制器从屏幕的最底部往上钻,直到盖住之前的控制器为止 ...

  6. hdu-1532 Drainage Ditches---最大流模板题

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1532 题目大意: 给出有向图以及边的最大容量,求从1到n的最大流 思路: 传送门:最大流的增广路算法 ...

  7. 8--oop

    oop-Python面向对象 Python的面向对象 面向对象编程 基础 共有私有 继承 组合,Mixin 魔法函数 魔法函数概述 构造类魔法函数 运算类魔法函数 1.面向对象概述(ObjectOri ...

  8. CUDA的软件体系

    CUDA的软件堆栈由以下三层构成:CUDA Library.CUDA runtime API.CUDA driver API,如图所示,CUDA的核心是CUDA C语言,它包含对C语言的最小扩展集和一 ...

  9. 深入理解new String()

    一. 引言 new String("hello")这样的创建方式,到底创建了几个String对象? 二. 分析 String s1 = "HelloWorld" ...

  10. fstatfs/statfs详解

    [fstatfs/statfs系统调用]       功能描述:   查询文件系统相关的信息.     用法:   #include <sys/vfs.h>    /* 或者 <sy ...