`

java多线程

 
阅读更多

摘要:

很多核心Java面试题来源于多线程(Multi-Threading)和集合框架(Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的。这篇文章收集了 Java 线程方面一些典型的问题,这些问题经常被高级工程师所问到。 很多核心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 类在独立的线程中调用这两个方法。

  1. public class Common {     
  2.     public synchronized void synchronizedMethod1() {    
  3.         System.out.println ("synchronizedMethod1 called");    
  4.         try {    
  5.             Thread.sleep (1000);    
  6.         } catch (InterruptedException e) {    
  7.             e.printStackTrace ();    
  8.         }    
  9.         System.out.println ("synchronizedMethod1 done");    
  10.     }    
  11.     public void method1() {    
  12.         System.out.println ("Method 1 called");    
  13.         try {    
  14.             Thread.sleep (1000);    
  15.         } catch (InterruptedException e) {    
  16.             e.printStackTrace ();    
  17.         }    
  18.         System.out.println ("Method 1 done");    
  19.     }    
  20. }   
  21. public class MyThread extends Thread {    
  22.     private int id = 0;    
  23.     private Common common;    
  24.      
  25.     public MyThread (String name, int no, Common object) {    
  26.         super(name);    
  27.         common = object;    
  28.         id = no;    
  29.     }    
  30.      
  31.     public void run () {    
  32.         System.out.println ("Running Thread" + this.getName ());    
  33.         try {    
  34.             if (id == 0) {    
  35.                 common.synchronizedMethod1();    
  36.             } else {    
  37.                 common.method1();    
  38.             }    
  39.         } catch (Exception e) {    
  40.             e.printStackTrace ();    
  41.         }    
  42.     }    
  43.      
  44.     public static void main (String[] args) {    
  45.         Common c = new Common ();    
  46.         MyThread t1 = new MyThread ("MyThread-1"0, c);    
  47.         MyThread t2 = new MyThread ("MyThread-2"1, c);    
  48.         t1.start ();    
  49.         t2.start ();    
  50.     }    
  51. }  
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 调用这两个方法。

  1. public class Common {    
  2.     public synchronized void synchronizedMethod1() {    
  3.         System.out.println ("synchronizedMethod1 called");    
  4.         try {    
  5.             Thread.sleep (1000);    
  6.         } catch (InterruptedException e) {    
  7.             e.printStackTrace ();    
  8.         }    
  9.         System.out.println ("synchronizedMethod1 done");    
  10.     }    
  11.      
  12.     public synchronized void synchronizedMethod2() {    
  13.         System.out.println ("synchronizedMethod2 called");    
  14.         try {    
  15.             Thread.sleep (1000);    
  16.         } catch (InterruptedException e) {    
  17.             e.printStackTrace ();    
  18.         }    
  19.         System.out.println ("synchronizedMethod2 done");    
  20.     }     
  21. }   
  22.   
  23.   
  24. public class MyThread extends Thread {    
  25.     private int id = 0;    
  26.     private Common common;    
  27.          
  28.     public MyThread (String name, int no, Common object) {    
  29.         super(name);    
  30.         common = object;    
  31.         id = no;    
  32.     }    
  33.      
  34.     public void run () {    
  35.         System.out.println ("Running Thread" + this.getName ());    
  36.         try {    
  37.             if (id == 0) {    
  38.                 common.synchronizedMethod1();    
  39.             } else {    
  40.                 common.synchronizedMethod2();    
  41.             }    
  42.         } catch (Exception e) {    
  43.             e.printStackTrace ();    
  44.         }    
  45.     }    
  46.      
  47.     public static void main (String[] args) {    
  48.         Common c = new Common ();    
  49.         MyThread t1 = new MyThread ("MyThread-1"0, c);    
  50.         MyThread t2 = new MyThread ("MyThread-2"1, c);    
  51.         t1.start ();    
  52.         t2.start ();    
  53.     }    
  54. }   
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 ()。
当所有线程卡在无限循环中。

这里的问题并不详尽,我相信还有很多重要的问题并未提及,您认为还有哪些问题应该包括在上面呢?欢迎在评论中分享任何形式的问题与建议。
本文转自:http://www.csdn.net/article/2012-05-28/2806046

分享到:
评论

相关推荐

    Java多线程知识点总结

    Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...

    java 多线程操作数据库

    ### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...

    Java多线程设计模式上传文件

    Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式...

    java多线程经典案例

    Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,极大地提升了程序的效率和性能。在Java中,实现多线程有两种主要方式:通过实现Runnable接口或者继承Thread类。本案例将深入探讨Java多线程中的关键...

    java多线程Demo

    Java多线程是Java编程中的一个重要概念,它允许程序同时执行多个任务,提高了程序的效率和响应速度。在Java中,实现多线程有两种主要方式:继承Thread类和实现Runnable接口。 1. 继承Thread类: 当我们创建一个新...

    java多线程的讲解和实战

    Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...

    java多线程分页查询

    ### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...

    汪文君JAVA多线程编程实战(完整不加密)

    《汪文君JAVA多线程编程实战》是一本专注于Java多线程编程的实战教程,由知名讲师汪文君倾力打造。这本书旨在帮助Java开发者深入理解和熟练掌握多线程编程技术,提升软件开发的效率和质量。在Java平台中,多线程是...

    java多线程ppt

    java多线程PPT 多线程基本概念 创建线程的方式 线程的挂起与唤醒 多线程问题

    java多线程读取文件

    Java多线程读大文件 java多线程写文件:多线程往队列中写入数据

    Java多线程机制(讲述java里面与多线程有关的函数)

    Java多线程机制是Java编程中至关重要的一部分,它允许程序同时执行多个任务,提升应用程序的效率和响应性。以下是对各个知识点的详细说明: 9.1 Java中的线程: Java程序中的线程是在操作系统级别的线程基础上进行...

    深入浅出 Java 多线程.pdf

    在本文中,我们将深入浅出Java多线程编程的世界,探索多线程编程的基本概念、多线程编程的优点、多线程编程的缺点、多线程编程的应用场景、多线程编程的实现方法等内容。 一、多线程编程的基本概念 多线程编程是指...

    java 多线程并发实例

    在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...

    JAVAJAVA多线程教学演示系统论文

    《JAVA多线程教学演示系统》是一篇深入探讨JAVA多线程编程的论文,它针对教育领域中的教学需求,提供了一种生动、直观的演示方式,帮助学生更好地理解和掌握多线程技术。这篇论文的核心内容可能包括以下几个方面: ...

    java多线程实现大批量数据导入源码

    本项目以"java多线程实现大批量数据导入源码"为题,旨在通过多线程策略将大量数据切分,并进行并行处理,以提高数据处理速度。 首先,我们需要理解Java中的线程机制。Java通过`Thread`类来创建和管理线程。每个线程...

    java多线程查询数据库

    综上所述,"java多线程查询数据库"是一个涉及多线程技术、线程池管理、并发控制、分页查询等多个方面的复杂问题。通过理解和掌握这些知识点,我们可以有效地提高数据库操作的效率和系统的响应速度。

    java 多线程编程实战指南(核心 + 设计模式 完整版)

    《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...

    JAVA多线程编程技术PDF

    这份“JAVA多线程编程技术PDF”是学习和掌握这一领域的经典资料,涵盖了多线程的全部知识点。 首先,多线程的核心概念包括线程的创建与启动。在Java中,可以通过实现Runnable接口或继承Thread类来创建线程。创建后...

    Java多线程编程核心技术_完整版_java_

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程《Java多线程编程核心技术》将...

    Java多线程编程实战指南(核心篇)

    Java多线程编程实战指南(核心篇) 高清pdf带目录 随着现代处理器的生产工艺从提升处理器主频频率转向多核化,即在一块芯片上集成多个处理器内核(Core),多核处理器(Multicore Processor)离我们越来越近了――如今...

Global site tag (gtag.js) - Google Analytics