很多核心Java面试题来源于多线程(Multi-Threading)和集合框架(Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的。这篇文章收集了 Java 线程方面一些典型的问题,这些问题经常被高级工程师所问到。
0.Java 中多线程同步是什么?
在多线程程序下,同步能控制对共享资源的访问。如果没有同步,当一个 Java 线程在修改一个共享变量时,另外一个线程正在使用或者更新同一个变量,这样容易导致程序出现错误的结果。
1.解释实现多线程的几种方法?
一 Java 线程可以实现 Runnable 接口或者继承 Thread 类来实现,当你打算多重继承时,优先选择实现 Runnable。
2.Thread.start ()与 Thread.run ()有什么区别?
Thread.start ()方法(native)启动线程,使之进入就绪状态,当 cpu 分配时间该线程时,由 JVM 调度执行 run ()方法。
3.为什么需要 run ()和 start ()方法,我们可以只用 run ()方法来完成任务吗?
我们需要 run ()&start ()这两个方法是因为 JVM 创建一个单独的线程不同于普通方法的调用,所以这项工作由线程的 start 方法来完成,start 由本地方法实现,需要显示地被调用,使用这俩个方法的另外一个好处是任何一个对象都可以作为线程运行,只要实现了 Runnable 接口,这就避免因继承了 Thread 类而造成的 Java 的多继承问题。
4.什么是 ThreadLocal 类,怎么使用它?
ThreadLocal 是一个线程级别的局部变量,并非“本地线程”。ThreadLocal 为每个使用该变量的线程提供了一个独立的变量副本,每个线程修改副本时不影响其它线程对象的副本(译者注)。
下面是线程局部变量(ThreadLocal variables)的关键点:
一个线程局部变量(ThreadLocal variables)为每个线程方便地提供了一个单独的变量。
ThreadLocal 实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程。
当多个线程访问 ThreadLocal 实例时,每个线程维护 ThreadLocal 提供的独立的变量副本。
常用的使用可在 DAO 模式中见到,当 DAO 类作为一个单例类时,数据库链接(connection)被每一个线程独立的维护,互不影响。(基于线程的单例)
ThreadLocal 难于理解,下面这些引用连接有助于你更好的理解它。
《Good article on ThreadLocal on IBM DeveloperWorks 》、《理解 ThreadLocal》、《Managing data : Good example》、《Refer Java API Docs》
5.什么时候抛出 InvalidMonitorStateException 异常,为什么?
调用 wait ()/notify ()/notifyAll ()中的任何一个方法时,如果当前线程没有获得该对象的锁,那么就会抛出 IllegalMonitorStateException 的异常(也就是说程序在没有执行对象的任何同步块或者同步方法时,仍然尝试调用 wait ()/notify ()/notifyAll ()时)。由于该异常是 RuntimeExcpetion 的子类,所以该异常不一定要捕获(尽管你可以捕获只要你愿意).作为 RuntimeException,此类异常不会在 wait (),notify (),notifyAll ()的方法签名提及。
6.Sleep ()、suspend ()和 wait ()之间有什么区别?
Thread.sleep ()使当前线程在指定的时间处于“非运行”(Not Runnable)状态。线程一直持有对象的监视器。比如一个线程当前在一个同步块或同步方法中,其它线程不能进入该块或方法中。如果另一线程调用了 interrupt ()方法,它将唤醒那个“睡眠的”线程。
注意:sleep ()是一个静态方法。这意味着只对当前线程有效,一个常见的错误是调用t.sleep (),(这里的t是一个不同于当前线程的线程)。即便是执行t.sleep (),也是当前线程进入睡眠,而不是t线程。t.suspend ()是过时的方法,使用 suspend ()导致线程进入停滞状态,该线程会一直持有对象的监视器,suspend ()容易引起死锁问题。
object.wait ()使当前线程出于“不可运行”状态,和 sleep ()不同的是 wait 是 object 的方法而不是 thread。调用 object.wait ()时,线程先要获取这个对象的对象锁,当前线程必须在锁对象保持同步,把当前线程添加到等待队列中,随后另一线程可以同步同一个对象锁来调用 object.notify (),这样将唤醒原来等待中的线程,然后释放该锁。基本上 wait ()/notify ()与 sleep ()/interrupt ()类似,只是前者需要获取对象锁。
7.在静态方法上使用同步时会发生什么事?
同步静态方法时会获取该类的“Class”对象,所以当一个线程进入同步的静态方法中时,线程监视器获取类本身的对象锁,其它线程不能进入这个类的任何静态同步方法。它不像实例方法,因为多个线程可以同时访问不同实例同步实例方法。
8.当一个同步方法已经执行,线程能够调用对象上的非同步实例方法吗?
可以,一个非同步方法总是可以被调用而不会有任何问题。实际上,Java 没有为非同步方法做任何检查,锁对象仅仅在同步方法或者同步代码块中检查。如果一个方法没有声明为同步,即使你在使用共享数据 Java 照样会调用,而不会做检查是否安全,所以在这种情况下要特别小心。一个方法是否声明为同步取决于临界区访问(critial section access),如果方法不访问临界区(共享资源或者数据结构)就没必要声明为同步的。
下面有一个示例说明:Common 类有两个方法 synchronizedMethod1()和 method1(),MyThread 类在独立的线程中调用这两个方法。
- public class Common {
- public synchronized void synchronizedMethod1() {
- System.out.println ("synchronizedMethod1 called");
- try {
- Thread.sleep (1000);
- } catch (InterruptedException e) {
- e.printStackTrace ();
- }
- System.out.println ("synchronizedMethod1 done");
- }
- public void method1() {
- System.out.println ("Method 1 called");
- try {
- Thread.sleep (1000);
- } catch (InterruptedException e) {
- e.printStackTrace ();
- }
- System.out.println ("Method 1 done");
- }
- }
- public class MyThread extends Thread {
- private int id = 0;
- private Common common;
- public MyThread (String name, int no, Common object) {
- super(name);
- common = object;
- id = no;
- }
- public void run () {
- System.out.println ("Running Thread" + this.getName ());
- try {
- if (id == 0) {
- common.synchronizedMethod1();
- } else {
- common.method1();
- }
- } catch (Exception e) {
- e.printStackTrace ();
- }
- }
- public static void main (String[] args) {
- Common c = new Common ();
- MyThread t1 = new MyThread ("MyThread-1", 0, c);
- MyThread t2 = new MyThread ("MyThread-2", 1, c);
- t1.start ();
- t2.start ();
- }
- }
这里是程序的输出:
- Running ThreadMyThread-1
- synchronizedMethod1 called
- Running ThreadMyThread-2
- Method 1 called
- synchronizedMethod1 done
- Method 1 done
结果表明即使 synchronizedMethod1()方法执行了,method1()也会被调用。
9.在一个对象上两个线程可以调用两个不同的同步实例方法吗?
不能,因为一个对象已经同步了实例方法,线程获取了对象的对象锁。所以只有执行完该方法释放对象锁后才能执行其它同步方法。看下面代码示例非常清晰:Common 类有 synchronizedMethod1()和 synchronizedMethod2()方法,MyThread 调用这两个方法。
- public class Common {
- public synchronized void synchronizedMethod1() {
- System.out.println ("synchronizedMethod1 called");
- try {
- Thread.sleep (1000);
- } catch (InterruptedException e) {
- e.printStackTrace ();
- }
- System.out.println ("synchronizedMethod1 done");
- }
- public synchronized void synchronizedMethod2() {
- System.out.println ("synchronizedMethod2 called");
- try {
- Thread.sleep (1000);
- } catch (InterruptedException e) {
- e.printStackTrace ();
- }
- System.out.println ("synchronizedMethod2 done");
- }
- }
- public class MyThread extends Thread {
- private int id = 0;
- private Common common;
- public MyThread (String name, int no, Common object) {
- super(name);
- common = object;
- id = no;
- }
- public void run () {
- System.out.println ("Running Thread" + this.getName ());
- try {
- if (id == 0) {
- common.synchronizedMethod1();
- } else {
- common.synchronizedMethod2();
- }
- } catch (Exception e) {
- e.printStackTrace ();
- }
- }
- public static void main (String[] args) {
- Common c = new Common ();
- MyThread t1 = new MyThread ("MyThread-1", 0, c);
- MyThread t2 = new MyThread ("MyThread-2", 1, c);
- t1.start ();
- t2.start ();
- }
- }
10.什么是死锁
死锁就是两个或两个以上的线程被无限的阻塞,线程之间相互等待所需资源。这种情况可能发生在当两个线程尝试获取其它资源的锁,而每个线程又陷入无限等待其它资源锁的释放,除非一个用户进程被终止。就 JavaAPI 而言,线程死锁可能发生在一下情况。
- 当两个线程相互调用 Thread.join ()
- 当两个线程使用嵌套的同步块,一个线程占用了另外一个线程必需的锁,互相等待时被阻塞就有可能出现死锁。
11.什么是线程饿死,什么是活锁?
线程饿死和活锁虽然不想是死锁一样的常见问题,但是对于并发编程的设计者来说就像一次邂逅一样。
当所有线程阻塞,或者由于需要的资源无效而不能处理,不存在非阻塞线程使资源可用。JavaAPI 中线程活锁可能发生在以下情形:
- 当所有线程在程序中执行 Object.wait (0),参数为 0 的 wait 方法。程序将发生活锁直到在相应的对象上有线程调用 Object.notify ()或者 Object.notifyAll ()。
- 当所有线程卡在无限循环中。
这里的问题并不详尽,我相信还有很多重要的问题并未提及,您认为还有哪些问题应该包括在上面呢?欢迎在评论中分享任何形式的问题与建议。
译文出自:jobbole
英文出自:fromdev
相关推荐
第二篇(第2章~第13章)介绍了Java程序员涉及的基础知识,内容包括Java语言基础、异常的处理、I/O控制流、面向对象编程、线程、集合以及数据库技术等基本知识点。 第三篇(第14章~第16章)专门介绍了Java开发...
除了理论知识外,《JAVA程序员面试宝典 第4版》还提供了丰富的实战案例分析,帮助读者更好地理解如何将所学知识应用于实际工作中。例如,在多线程编程部分,书中通过具体示例展示了如何利用synchronized关键字和...
【Java面试核心知识点详解】 1. **面向对象的特征**: - **抽象**:抽象是将复杂的现实问题简化,关注关键属性和行为,忽略不重要的细节。...理解和掌握这些知识点对于提升Java程序员的技能水平至关重要。
《程序员面试金典5》是一本深受欢迎的面试准备指南,尤其对于想要在Java和C++领域求职的程序员来说,更是必备的参考资料。这本书涵盖了广泛的编程语言基础、数据结构、算法以及软件工程等方面的知识,旨在帮助读者...
【Java面试题全集2021版】涵盖了Java编程语言及与其相关的各种技术领域的面试问题,旨在帮助求职者准备面试。以下是一些关键的知识点: 1. **基础语法**: - 数据类型:了解基本数据类型(如int、float、char)与...
这本书旨在帮助Java程序员深入理解技术原理,提升面试表现,为他们在职场竞争中赢得优势。 在Java编程语言部分,你可以学习到基础语法、面向对象特性,如封装、继承和多态,以及异常处理、集合框架等核心内容。深入...
### 2019最新Java程序员初中级面试宝典知识点详解 #### Java基础部分 **&与&&的区别** - **&**: 这是位运算符,也可以作为逻辑运算符使用。当它用作逻辑运算符时,其作用是判断两边同时为真时结果为真,否则为假...
多线程是Java中的高级主题,面试者需要了解线程的创建、同步、通信以及死锁的概念。synchronized关键字、volatile变量、ThreadLocal、wait()、notify()等方法的使用也是面试常考内容。 Java I/O系统是处理输入输出...
Java作为世界上最受欢迎的编程语言之一,其面试题的覆盖面广泛且深入,涵盖了语言基础、面向对象、多线程、集合框架、JVM、网络、数据库、设计模式等多个方面。以下是一些可能出现的重要Java面试知识点: 1. **Java...
- **性能问题**:Java 的运行速度通常较慢且占用更多资源,这主要是因为 Java 程序是以字节码形式运行的,需要通过 JVM 来解释执行,而 C++ 程序则是直接编译成二进制代码,无需额外的解释层。 - **内存管理**:Java...
Java面试大全涵盖了许多核心知识点,是准备Java程序员面试的重要资源。以下是一些主要的Java面试笔试题相关的知识点,包括但不限于: 1. **基础语法**:理解基本数据类型、变量、运算符、流程控制(if、switch、for...
在 Java 面试中,了解一些基础知识点是非常重要的。本文将对 Java 基础面试题进行详细的解释,包括 final、finally、finalize 的区别、Anonymous Inner Class、& 和 && 的区别、HashMap 和 Hashtable 的区别、...
Java面试题涵盖了许多核心概念,这里我们逐一解析: 1. J2EE(Java 2 Platform, Enterprise Edition)是一个用于开发和部署企业级应用程序的平台,它...理解和掌握这些知识点对于提升Java程序员的专业能力至关重要。
│ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+Hibernate+Spring轻量级J2EE企业应用实战.pdf │ Struts中文手册.pdf │ ...
│ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+Hibernate+Spring轻量级J2EE企业应用实战.pdf │ Struts中文手册.pdf │ ...
Java面试题目精华主要涵盖了许多Java基础和进阶的知识点,以下是对这些知识点的详细解析: 1. **异常处理**:Java中的异常处理是...以上就是Java面试中常见的知识点,理解和掌握这些内容对于准备Java面试非常有帮助。
Java面试笔试题大汇总涵盖了Java语言的核心概念以及面试中常见的技术问题。以下是对这些知识点的详细解释: ...这些知识点是Java程序员面试中常见的考察点,理解并掌握它们对于提升技术水平和面试成功至关重要。
1. **线程同步**:Java提供多种机制来保证多线程环境下的数据一致性,如`synchronized`关键字、显式锁等。 2. **线程池**:合理使用线程池可以有效管理线程资源,避免频繁创建和销毁线程带来的性能开销。 #### 八...
Java作为一门广泛使用的编程语言,其面试笔试题涵盖了众多领域,包括基础语法、面向对象、集合框架、多线程、JVM、网络编程、数据库操作、设计模式等。以下是对这些知识点的详细解读: 1. **Java基础语法**:这是...
3. **技能清单**:列出你的核心技术能力,如Java SE/EE、Spring框架、JPA/Hibernate、多线程、并发编程、数据库管理(MySQL、Oracle等)以及常用的开发工具(Eclipse、IntelliJ IDEA等)。 4. **项目经验**:详述你...