多线程和并发面试问题与答案(3)

已有 3350人阅读此文 - - 经验分享

多线程和并发面试问题与答案(1)


多线程和并发面试问题与答案(2)


多线程和并发面试问题与答案(4)


多线程和并发面试问题与答案(5)

21. 一个线程在被放在使用线程休眠Thread.sleep()前怎么被唤醒?

java.lang.Thread 的方法 interrupt() 可以中断睡眠线程. 中断线程通过调用 Thread.sleep() 进入睡眠,会被InterruptedException唤醒:

public class InterruptExample implements Runnable {

	public void run() {
		try {
			Thread.sleep(Long.MAX_VALUE);
		} catch (InterruptedException e) {
			System.out.println("["+Thread.currentThread().getName()+"] Interrupted by exception!");
		}
	}

	public static void main(String[] args) throws InterruptedException {
		Thread myThread = new Thread(new InterruptExample(), "myThread");
		myThread.start();

		System.out.println("["+Thread.currentThread().getName()+"] Sleeping in main thread for 5s...");
		Thread.sleep(5000);

		System.out.println("["+Thread.currentThread().getName()+"] Interrupting myThread");
		myThread.interrupt();
	}
}

22. 怎么查询一个线程是否已经中断?

如果线程不是在一个方法里像 Thread.sleep() 抛出一个 InterruptedException异常.线程可以通过调用静态方法 Thread.interrupted() 或者从java.lang.Thread 继承的isInterrupted()查询是否已中断.

23. 应如何处理一个InterruptedException 异常?

方法例如 sleep() and join()会抛出 InterruptedException 异常告诉调用者另一个线程已经中断该线程. 在大多数情况下,这样做是为了让当前线程停止当前计算和意外地结束。因此忽略这种异常,仅仅捕获例外和记录在控制台或日志文件通常不是处理这种异常的适当方法. 不过这异常的问题是Runnable接口的方法 run() 不允许 run()抛出任何异常. 所以重新抛出并没有帮助. 所以这意味着 run() 的实现本身必须处理受检异常,这往往导致其被捕获和被忽视.

24. 在启动子线程后,我们如何在父线程等待子线程终止?

等待一个线程的终止是通过对线程的实例变量调用方法 join():

Thread thread = new Thread(new Runnable() {
	@Override
	public void run() {

	}
});
thread.start();
thread.join();

25. 下列程序的输出是什么?

public class MyThreads {

	private static class MyDaemonThread extends Thread {

		public MyDaemonThread() {
			setDaemon(true);
		}

		@Override
		public void run() {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
		}
	}

	public static void main(String[] args) throws InterruptedException {
		Thread thread = new MyDaemonThread();
		thread.start();
		thread.join();
		System.out.println(thread.isAlive());
	}
}

上述代码的输出是 “false”. 虽然 MyDaemonThread 实例是守护线程, 调用的 join() 导致主线程等待守护线程执行完毕. 因此,在线程实例调用 isAlive() 会导致守护线程不再运行.

26.当未捕获的异常逃逸 run()方法?

一个不受检查的异常有可能从run() 方法逃逸. 在这种情况下, 该线程被Java虚拟机停止. UncaughtExceptionHandler 作为例外处理程序的接口,通过注册其实例, 来捕获此异常. 这要么是在线程本身没有特定处理,通过调用静态方法Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)告诉JVM使用所提供的处理程序, 或者通过调用线程实例本身setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler).

27. 什么是关闭钩子?

关闭钩子是JVM关闭线程时执行的线程. 通过调用Runtime 实例上面 addShutdownHook(Runnable) 方法可以注册它:

Runtime.getRuntime().addShutdownHook(new Thread() {
	@Override
	public void run() {

	}
});

28. 关键字synchronized什么目的下使用?

当你必须实现资源的专用访问,像一些静态值或某些文件的引用,工作于专用资源的代码就可以使用synchronized块:

synchronized (SynchronizedCounter.class) {
	counter++;
}

29. 同步方法获取有什么内在锁?

一个synchronized方法获得该方法对象的内在锁,并在返回的时候释放它的方法。即使方法抛出一个异常,内在锁被释放。因此,一个同步方法是等于以下代码:

public void method() {
	synchronized(this) {
		...
	}
}

30. 构造方法可以同步?

不,构造方法不能同步。这导致了语法错误,事实是只有正在构造的线程应该能够访问所构成的对象.

31. 原始值可以用于内部锁?

不,原始值不能用于内部锁.

32. 内部锁重入么?

是的,内在锁可以被同一个线程中一次又一次访问,需要获得锁的代码必须注意它可以不小心试图获取一个它已经获得了的锁.

33. 我们怎么理解原子操作?

一个原子操作就是要么完全执行或根本不执行的操作.

34. 语句C + +是否原子性?

不,一个整数型变量的增加包含一个以上的操作。首先我们得到C的现值,然后增加,最后存储新的价值。当前线程执行这个策略,可能会在任何这些三步骤之间中断,因此这不是原子操作.

35.什么操作是原子操作?

Java语言提供一些原子性的基本操作,因此可以被用来确保并发线程总是看到相同的值的:

  • 参考变量和原始变量(除了long和double)的读写操作

  • 所有声明为volatile变量的读写操作

36. 下面代码是否为线程安全?

public class DoubleCheckedSingleton {
	private DoubleCheckedSingleton instance = null;

	public DoubleCheckedSingleton getInstance() {
		if(instance == null) {
			synchronized (DoubleCheckedSingleton.class) {
				if(instance == null) {
					instance = new DoubleCheckedSingleton();
				}
			}
		}
		return instance;
	}
}

上面的代码是线程不安全的。虽然它在同步代码块(出于性能原因)再次检查实例的值,JIT编译器可以重新排列字节码,在构造函数完成执行之前改变实例的引用的这种方式。这意味着,该方法 getInstance() 返回一个对象,可能没有被完全初始化。要使代码是线程安全的,Java 5提供了实例变量的关键字volatile。一旦对象的构造函数完全完成执行,被标记为volatile变量才对其他线程可见的.

37. 我们所理解的死锁?

死锁的情况是在两个(或更多)的线程都在等待另一个线程释放资源,而线程本身已锁定其他线程等待的资源:线程1:锁资源A,等待资源B,线程2:锁资源B,等待资源A.

38. 一个死锁的情况有什么要求?

一般按下面条件,可以识别死锁:

  • 互斥: 一个资源在任何时间点上只能用一个线程访问.

  • 资源保持: 线程锁定一个资源,同时试图获取在另一个锁的一些独家资源.

  • 非剥夺条件: 如果一个线程持有一段时间锁,没有机制释放资源.

  • 环路等待: 运行时的一个环形链,两个(或更多)的线程都在等待另一个线程释放它已锁定资源.

39. 是否可能防止死锁的发生呢?

为了防止死锁的一个(或更多)死锁,死锁的一些条件要避免:

  • 互斥: 在某些情况下可以用乐观锁防止相互排斥.

  • 资源保持: 当一个线程没有获得所有的排它锁,它可能会释放它所有的排它锁.

  • 非剥夺条件: 使用一个超时,排它锁在一个给定的时间后释放锁.

  • 循环等待: 当所有线程在同一序列访问对象,就不会发生循环等待.

40. 有可能实现一个死锁检测?

当所有的排他锁被监测和建模为一个有向图,死锁检测系统可以搜索两个线程是否互相等待对方释放它们已锁定的资源。等待线程可以通过某种异常被迫释放其他线程正在等待的锁.

多线程和并发面试问题与答案(1)


多线程和并发面试问题与答案(2)


多线程和并发面试问题与答案(4)


多线程和并发面试问题与答案(5)


期待你一针见血的评论,Come on!