面试相关的技术问题--多线程

本文中意在整理关于多线程相关的面试问题,借助了网络上部分关于问题的解答过程,此处不做出处标记,仅供记录学习,以备遗忘!!!文中如果有讲述不妥或者错误的地方,希望阅者给我留言。

1.多线程的实现方式
Java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。


2.线程的状态转换

 


3.如何停止一个线程

1). 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2). 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。
3). 使用interrupt方法中断线程。


4.什么是线程安全,如何保证线程安全

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
保证线程安全的方法:
不要跨线程访问共享变量
使共享变量是final类型的
将共享变量的操作加上同步


5. Synchronized如何使用
1).方法声明时使用

public synchronized void synMethod() {
//方法体
}

2).对某一代码块使用,synchronized后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块.此时,线程获得的是成员锁

public int synMethod(int a1){
synchronized(a1) {
//一次只能有一个线程进入
}
}

3). synchronized后面括号里是一对象,此时,线程获得的是对象锁。

public class MyThread implements Runnable {
public static void main(String args[]) {
MyThread mt = new MyThread();
Thread t1 = new Thread(mt, "t1");
Thread t2 = new Thread(mt, "t2");
Thread t3 = new Thread(mt, "t3");
Thread t4 = new Thread(mt, "t4");
Thread t5 = new Thread(mt, "t5");
Thread t6 = new Thread(mt, "t6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName());
}
}
} 

如果线程进入,则得到当前对象锁,那么别的线程在该类所有对象上的任何操作都不能进行.在对象级使用锁通常是一种比较粗糙的方法。为什么要将整个对象都上锁,而不允许其他线程短暂地使用对象中其他同步方法来访问共享资源?如果一个对象拥有多个资源,就不需要只为了让一个线程使用其中一部分资源,就将所有线程都锁在外面
4).synchronized后面括号里是类,此时,线程获得的是对象锁.


6. synchronized和Lock的区别
主要相同点:Lock能完成synchronized所实现的所有功能
不同:
1).ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。
2).ReentrantLock必须在finally中释放锁,否则后果很严重,编码角度来说使用synchronized更加简单,不容易遗漏或者出错。
3).ReentrantLock 的性能比synchronized会好点。
4).ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。


7. sleep和wait的区别(考察的方向是是否会释放锁)
对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程中,线程不会释放对象锁。而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。


8. 如何才能产生死锁
产生死锁的必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。


9. 什么叫守护线程,用什么方法实现守护线程
  public final void setDaemon(boolean on)


10. volatile关键字
 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
  1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  2)禁止进行指令重排序
volatile关键字保证了操作的可见性,但是volatile不能保证对变量的操作是原子性
volatile关键字能禁止指令重排序,所以volatile能在一定程度上保证有序性
借用深入学习JAVA虚拟机中的一段话:
观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令

 

posted @ 2016-08-29 11:09  爪哇小生  阅读(309)  评论(0编辑  收藏  举报