1. sleep() 和 wait() 有什么区别?
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
2. 同步和异步
为了在线程之间进行可靠的通信,也为了互斥访问,同步是必须的。这归因于Java语言规范的内存模型,它规定了:一个线程所做的变化何时以及如何变成对其它线程可见。
因为多线程将异步行为引进程序,所以在需要同步时,必须有一种方法强制进行。例如:如果2个线程想要通信并且要共享一个复杂的数据结构,如链表,此时需要确保它们互不冲突,也就是必须阻止B线程在A线程读数据的过程中向链表里面写数据(A获得了锁,B必须等A释放了该锁)。
为了达到这个目的,java在一个旧的的进程同步模型——监控器(Monitor)的基础上实现了一个巧妙的方案:监控器是一个控制机制,可以认为是一个很小的、只能容纳一个线程的盒子,一旦一个线程进入监控器,其它的线程必须等待,直到那个线程退出监控为止。通过这种方式,一个监控器可以保证共享资源在同一时刻只可被一个线程使用。这种方式称之为同步。(一旦一个线程进入一个实例的任何同步方法,别的线程将不能进入该同一实例的其它同步方法,但是该实例的非同步方法仍然能够被调用)。
错误的理解:同步嘛,就是几个线程可以同时进行访问。
小结:为了防止多个线程并发对同一数据的修改,所以需要同步,否则会造成数据不一致(就是所谓的:线程安全。如java集合框架中Hashtable和Vector是线程安全的。我们的大部分程序都不是线程安全的,因为没有进行同步,而且我们没有必要,因为大部分情况根本没有多线程环境)。
混淆:
普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完返回 这个期间客户端浏览器不能干任何事
异步:请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
可见,彼“同步”非此“同步”——我们说的java中的那个共享数据同步(synchronized)
一个同步的对象是指行为(动作),一个是同步的对象是指物质(共享数据)。
Java同步机制有4种实现方式:
① ThreadLocal ②synchronized( ) ③ wait() 与 notify() ④ volatile
目的:都是为了解决多线程中的对同一变量的访问冲突
ThreadLocal
ThreadLocal 保证不同线程拥有不同实例,相同线程一定拥有相同的实例,即为每一个使用该变量的线程提供一个该变量值的副本,每一个线程都可以独立改变自己的副本,而不是与其它线程的副本冲突。
优势:提供了线程安全的共享对象
与其它同步机制的区别:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信;而 ThreadLocal 是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源,这样当然不需要多个线程进行同步了。
synchronized (重点)
http://blog.csdn.net/chenallen1025/article/details/7887166
3. 怎么保证多线程之间的线程安全
1, 保证线程安全的三种方法:a,不要跨线程访问共享变量b,使共享变量是final类型的c,将共享变量的操作加上同步。
2,必要时,使用ThreadLocal变量确保线程封闭性(封闭线程往往是比较安全的,但一定程度上会造成性能损耗)封闭对象的例子在实际使用过程中,比较常见,例如hibernate openSessionInView机制,jdbc的connection机制。
4. 模拟死锁:
public class ThreadTest implements Runnable {
private Object o1 = new Object();
private Object o2 = new Object();
public int value = 0; // 起一个标志作用
public static void main(String[] args) throws InterruptedException {
ThreadTest t1 = new ThreadTest();
t1.value = 0;
new Thread(t1).start();
// 让当前线程睡眠
Thread.sleep(500);
// 修改value的值
t1.value = 1;
new Thread(t1).start();
}
public void run() {
if (value == 0) {
synchronized (o1) {
System.out.println("线程A :我得到了o1的锁");
try {
// 让当前线程睡眠,从而让另外一个线程可以先得到对象o2的锁
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A :我还想要得到o2的锁");
// 在得到o1锁之后,又想得到o2的锁
synchronized (o2) {
System.out.println("线程A :我得到了o2的锁");
}
}
} else {
synchronized (o2) {
System.out.println("线程B :我得到了o2的锁");
try {
// 让当前线程睡眠,从而让另外一个线程可以先得到对象o1的锁
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程B :我还想要得到o1的锁");
// 在得到o2锁之后,又想得到o1的锁
synchronized (o1) {
System.out.println("线程B :我得到了o1的锁");
}
}
}
}
}
5. 启动一个线程是用run()还是start()?
启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。
6. 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
不能,一个对象的一个synchronized方法只能由一个线程访问。
7. 线程的基本概念、线程的基本状态以及状态之间的关系?
线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。Java中的线程有四种状态分别是:运行、就绪、挂起、结束。
8. 简述synchronized和java.util.concurrent.locks.Lock的异同?
主要相同点:Lock能完成synchronized所实现的所有功能主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
9. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?有两种实现方法,分别是继承Thread类与实现Runnable接口。用synchronized关键字修饰同步方法。反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被“挂起”的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。
10. 线程的同步、如何实现线程的同步?
答:当两个或多个线程同时访问同一个变量,并且1个线程需要修改这个变量。就要用到线程同步。在Java 中,同步是通过 synchronized 关键字来定义的。 诺是想同步化某程序段,可以使用 synchronized(object){}方法,其中{}内的程序语句被同步化。
11. 用java怎样实现多线程?线程有那些状态?
答:Java 中实现多线程的方法有两种,一是继承 java.lang包中的 Thread 类,二是用户自己的类实现 Runnable 接口。初始状态,就绪状态,阻塞状态,运行状态,死亡状态。
12. 请说出你所知道的线程同步的方法。
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
13. 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口.
同步的实现方面有两种.分别是synchronized,wait与notify(了解原理)
14.一道关于java线程的面试题
class MyThread extends Thread{
public void run(){
System.out.println("MyThread: run()");
}
public void start(){
System.out.println("MyThread: start()");
}
}
class MyRunnable implements Runnable{
public void run(){
System.out.println("MyRunnable: run()");
}
public void start(){
System.out.println("MyRunnable: start()");
}
}
MyThread myThread = new MyThread();
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
myThread.start();
thread.start();
伤处程序执行结果是什么?
答案:
MyThread: start()
MyRunnable: run()
分析:
(一)MyThread 继承自 Thread,且覆盖了start()方法,所以当其实例start()时,不会在执行run()方法中的代码。其实这也是个“没用的线程了”。
所以先打印:MyThread: start() 。
(二)MyRunnable 实现了Runnable 接口,Runnable 接口就一个run()方法。
Thread thread = new Thread(myRunnable); 这句代码,根据Runnable 的实例创建了一个Thread实例,该Thread实例的start方法会执行run()方法中的代码。
所以又打印:MyRunnable: run()
总结,Runnable 接口,就一个方法 :run() 。本人觉得这个接口仅仅是一种标记而已(类似 Serializable),或者为了以后扩展使用。而真正有意义的是它的实现:Thread。