线程的生命周期:新建、就绪、运行、阻塞、死亡
1、实现线程是继承Thread类好,还是实现Runnable接口好?
由于类不支持多重继承,如果要继承其他类,最好是实现线程用Runnable
2、Thread类的start()方法和run()方法的区别
start被用来启动新创建的线程,内部调用了run方法,这跟直接调用run方法的效果是不一样的。当你调用run方法的时候,只会在原来的线程中调用,没有新的线程启动,start方法才会启动新线程。
3、Java的Runnable和Callable有什么不同
Callable的call()方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能
4、Java的volatile变量是什么?
volatile是一个特殊的修饰符,只有成员变量才能使用它,保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了这个变量的值,这个新值对于其他线程来说,是立即可见的。
5、Java中notify和notifyAll的区别
notify()方法不能唤醒某个具体的线程,只有当一个线程是等待的时候,它才能用;
notifyAll()方法唤醒所有线程并允许他们争夺锁,这样确保了至少有一个线程是能继续运行的;
5.1、wait()、notify()、notifyAll()方法为什么不在Thread类里面?
这几个方法是Object类的方法。Java提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得;
wait()、notify()、notifyAll()都属于锁级别的操作,所以把它们定义在Object中,因为锁属于对象;
5.2 wait()和notify()方法为什么要在同步块中调用?
Java API强制要求这样做,否则会抛出IllegalMonitorStateException异常,另一个原因是避免wait和notify之间产生竞态条件。
5.3 为什么应该在循环中检查等待条件?
处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。
因此当一个等待线程醒来时,不能认为它原来的等待状态仍然是有效的,在notify()方法调用之后和等待线程醒来之前这段时间,它可能会改变。
6、Java中堆和栈对于线程的作用
每个线程都有自己的栈内存,用于存储本地变量、方法参数、和栈调用。一个线程中存储的变量对其他线程是不可见的;
堆是所有线程共享的公共内存区域,对象都在堆里创建,为了提升效率,线程会从堆里弄一个缓存到自己的栈,如果多个线程使用该变量就可能引发问题,此时volatile变量就可以发挥作用,它要求线程从主存中读取变量的值。
7、FutureTask是什么?
在Java并发程序中FutureTask表示一个可以取消的异步运算;
它有启动和取消运算、查询运算是否完成和取回运算结果等方法;
只有当运算完成的时候结果才能取回,若运算未完成,get方法将会阻塞;
一个FutureTask对象可以对调用了Callable和Runnable的对象进行包装,由于FutureTask也是调用了Runnable接口,所以它可以提交给Executor来执行。
8、Java中interrupted和isInterrupted方法的区别
主要区别就是interrupted()方法会将中断状态清除,而isInterrupted()方法不会;
Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()方法来提示线程应该中断了,并设置中断标识为true。当中断线程调用静态方法Thread.interrupted()方法来检查中断状态时,发现中断标识为true则抛出InterruptedException异常,并将中断状态清零。而非静态方法isInterrupted()用来查询其他线程的中断状态且不会改变中断状态标识。
9、如何避免死锁?
死锁指的是两个或以上进程在执行过程中,因争夺资源而造成的一种相互等待的想象;
死锁发生的四个必要条件:
(1)互斥条件:一个资源每次只能呗一个进程使用;
(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;
(3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺;
(4)循环等待条件:若干进程之间形成一种头尾衔接的循环等待资源关系。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序做操作,来避免死锁。
10、如何检测一个线程是否拥有锁?
Thread.holdsLock()方法,返回true ,则说明当前线程拥有某个具体对象的锁。
11、Java中synchronized和ReentrantLock有什么不同?
synchronized关键字来实现互斥,但是不能扩展锁之外的方法或块边界,尝试获取锁时不能中途取消;
Java 5提供Lock接口来解决这些问题,ReentrantLock类实现了Lock接口,拥有与synchronized相同的并发性和内存语义,还具有可扩展性。
12、Java中的ReadWriteLock是什么?
读写锁是用来提升并发程序性能的锁分离技术。
ReadWriteLock维护一对关联锁,一个用于只读操作一个用于写。在没有写线程的情况下一个读锁可能会同时被多个读线程持有。写锁是独占的,可使用ReentrantReadWriteLock来实现。
13、volatile变量和atomic变量的区别?
volatile变量保证写操作发生在后续的读操作之前,但不能保证原子性;
AtomicInteger类提供的atomic方法可以让这种操作具有原子性,如getAndIncrement()方法会原子性的进行增量操作。
14、若同步块内的线程抛出异常会发生什么?
会释放锁。(其实无论同步块是正常还是异常退出,线程都会释放锁,在finally块里实现释放锁)