JAVA多线程 问题 转载

1.Java 中多线程同步是什么?

在多线程程序下,同步能实现控制对共享资源的访问。如果没有同步,当一个 Java 线程在修改一个共享变量时,另外一个线程正在使用或者更新同一个变量,这样容易导致程序出现错误的结果。

2.解释实现多线程的几种方法?

1>  Java 线程可以实现 Runnable 接口:(当你打算多重继承时,优先选择实现 Runnable)

[java]

  1. class Foo implements Runnable {
  2. public void run(){
  3. //...
  4. }
  5. }
  6. Thread t = new Thread(new Foo());
  7. t.start();

2> 继承 Thread 类来实现:

[java]

  1. class MyThread extends Thread {
  2. public void run() {
  3. ……   }
  4. }

3、Thread.start ()与 Thread.run ()有什么区别?

Thread.start ()方法启动线程,使之进入就绪状态,当 cpu 分配时间该线程时,由 JVM 调度执行 run ()方法。start()并不代表线程立即可以执行了。

4、为什么需要 run ()和 start ()方法,我们可以只用 run ()方法来完成任务吗?

我们需要 run ()和start ()这两个方法是因为 JVM 创建一个单独的线程不同于普通方法的调用,所以这项工作由线程的 start 方法来完成,start 由本地方法实现,需要显示地被调用,使用这俩个方法的另外一个好处是任何一个对象都可以作为线程运行,只要实现了 Runnable 接口,这就避免因继承了 Thread 类而造成的 Java 的多继承问题。

5、什么是 ThreadLocal 类,怎么使用它?

该类提供了线程局部变量。这些变量不同于它们的普通对应物,因为访问一个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的私有静态字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。

例如,在下面的类中,私有静态 ThreadLocal 实例(serialNum)为调用该类的静态 SerialNum.get() 方法的每个线程维护了一个“序列号”,该方法将返回当前线程的序列号。(线程的序列号是在第一次调用 SerialNum.get() 时分配的,并在后续调用中不会更改。)

[java]

  1. public class SerialNum {
  2. // The next serial number to be assigned
  3. private static int nextSerialNum = 0;
  4. private static ThreadLocal serialNum = new ThreadLocal() {
  5. protected synchronized Object initialValue() {
  6. return new Integer(nextSerialNum++);
  7. }
  8. };
  9. public static int get() {
  10. return ((Integer) (serialNum.get())).intValue();
  11. }
  12. }

每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。

6、什么时候抛出 IillegalMonitorStateException 异常,为什么?

调用 wait ()/notify ()/notifyAll ()中的任何一个方法时,如果当前线程没有获得该对象的锁,那么就会抛出 IllegalMonitorStateException 的异常(也就是说程序在没有执行对象的任何同步块或者同步方法时,仍然尝试调用 wait ()/notify ()/notifyAll ()时)。由于该异常是 RuntimeExcpetion 的子类,所以该异常不一定要捕获(尽管你可以捕获只要你愿意).作为 RuntimeException,此类异常不会在 wait (),notify (),notifyAll ()的方法签名提及。

7、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 ()类似,只是前者需要获取对象锁。

8、.在静态方法上使用同步时会发生什么事?

同步静态方法时会获取该类的“Class”对象,所以当一个线程进入同步的静态方法中时,线程监视器获取类本身的对象锁,其它线程不能进入这个类的任何静态同步方法。它不像实例方法,因为多个线程可以同时访问不同实例同步实例方法。

9、当一个同步方法已经执行,线程能够调用对象上的非同步实例方法吗?

可以,一个非同步方法总是可以被调用而不会有任何问题。实际上,Java 没有为非同步方法做任何检查,锁对象仅仅在同步方法或者同步代码块中检查。如果一个方法没有声明为同步,即使你在使用共享数据 Java 照样会调用,而不会做检查是否安全,所以在这种情况下要特别小心。一个方法是否声明为同步取决于临界区访问(critial section access),如果方法不访问临界区(共享资源或者数据结构)就没必要声明为同步的。

下面有一个示例说明:Common 类有两个方法 synchronizedMethod1()和 method1(),MyThread 类在独立的线程中调用这两个方法。

[java]

  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. public MyThread (String name, int no, Common object) {
  25. super(name);
  26. common = object;
  27. id = no;
  28. }
  29. public void run () {
  30. System.out.println (“Running Thread” + this.getName ());
  31. try {
  32. if (id == 0) {
  33. common.synchronizedMethod1();
  34. } else {
  35. common.method1();
  36. }
  37. } catch (Exception e) {
  38. e.printStackTrace ();
  39. }
  40. }
  41. public static void main (String[] args) {
  42. Common c = new Common ();
  43. MyThread t1 = new MyThread (“MyThread-1″, 0, c);
  44. MyThread t2 = new MyThread (“MyThread-2″, 1, c);
  45. t1.start ();
  46. t2.start ();
  47. }
  48. }

这里是程序的输出:

Running ThreadMyThread-1
synchronizedMethod1 called
Running ThreadMyThread-2
Method 1 called
synchronizedMethod1 done
Method 1 done

结果表明即使 synchronizedMethod1()方法执行了,method1()也会被调用。

10、在一个对象上两个线程可以调用两个不同的同步实例方法吗?

不能,因为一个对象已经同步了实例方法,线程获取了对象的对象锁。所以只有执行完该方法释放对象锁后才能执行其它同步方法。看下面代码示例非常清晰:Common 类有 synchronizedMethod1()和 synchronizedMethod2()方法,MyThread 调用这两个方法。

[java]

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

11、什么是死锁

死锁就是两个或两个以上的线程被无限的阻塞,线程之间相互等待所需资源。这种情况可能发生在当两个线程尝试获取其它资源的锁,而每个线程又陷入无限等待其它资源锁的释放,除非一个用户进程被终止。就 JavaAPI 而言,线程死锁可能发生在一下情况。

当两个线程相互调用 Thread.join ()
      当两个线程使用嵌套的同步块,一个线程占用了另外一个线程必需的锁,互相等待时被阻塞就有可能出现死锁。
12、什么是线程饿死,什么是活锁?

线程饿死和活锁虽然不想是死锁一样的常见问题,但是对于并发编程的设计者来说就像一次邂逅一样。

当所有线程阻塞,或者由于需要的资源无效而不能处理,不存在非阻塞线程使资源可用。JavaAPI 中线程活锁可能发生在以下情形:

当所有线程在程序中执行 Object.wait (0),参数为 0 的 wait 方法。程序将发生活锁直到在相应的对象上有线程调用 Object.notify ()或者 Object.notifyAll ()。
              当所有线程卡在无限循环中。

时间: 2024-11-20 12:32:42

JAVA多线程 问题 转载的相关文章

Java多线程总结(转载)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是Java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并发编程与技术内幕:线程池深入理解),或者看这个专栏:Java并发编程与技术内幕.你将会对Java里头的高并发场景下的线程有更加深刻的理解. 目录(?)[-] 一扩展javalan

(转载)Java多线程入门理解

转载出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并发编程与技术内幕:线程池深入理解),或者看这个专栏:Java并发编程与技术内幕.你将会对Java里头的高并发场景下的线程有更加深刻的理解. 目录(?)[-] 一扩展javalangThread类 二实现javalan

Java多线程编程模式实战指南(二):Immutable Object模式--转载

本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-immutable-object.转载请注明作者: 黄文海 出处:http://viscent.iteye.com. 多线程共享变量的情况下,为了保证数据一致性,往往需要对这些变量的访问进行加锁.而锁本身又会带来一些问题和开销.Immutable Object模式使得我们可以在不使用锁的情况下,既保证共享变量访问的线程安

[转载] java多线程学习-java.util.concurrent详解(一) Latch/Barrier

转载自http://janeky.iteye.com/blog/769965 Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可以帮助开发者编写高效.易维护.结构清晰的Java多线程程序.从这篇blog起,我将跟大家一起共同学习这些新的Java多线程构件 1. CountDownLatch     我们先来学习一下JDK1.5 API中关于这个类的详细介绍: “一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个

JAVA多线程和并发基础面试问答(转载)

原文链接:http://www.cnblogs.com/dolphin0520/p/3932934.html 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题. Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含

Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3534050.html Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可

JAVA多线程实现的三种方式

JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程. 当中前两种方式线程运行完后都没有返回值,仅仅有最后一种是带返回值的. 1.继承Thread类实现多线程 继承Thread类的方法虽然被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,而且,启动线程的唯一方法就是通过Thread类的start()实例方法.start(

java多线程系类:JUC原子类:03之AtomicLongArray原子类

概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数组类型的原子类进行介绍.内容包括:AtomicLongArray介绍和函数列表AtomicLongArray源码分析(基于JDK1.7.0_40)AtomicLongArray示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3514604.html

Java多线程<1>

1.Java多线程的概念: 线(Thread):它指的是一个任务的从开始执行流程到结束. 穿线提供执行任务的机构.供java条款.在一个程序可以启动多个并发线程.候执行. 在单处理器系统中,多个线程共享CPU时间,而操作系统负责调度及分配资源给它们.当程序作为一个应用程序来执行时.JAVA解释器为main开启一个线程. 当程序为Applet执行时,Web浏览器启动一个线程来执行applet.还能够在程序中创建附加的线程以执行并发任务. 在JAVA中,每一个任务都是Runnable的实例. 2.创