多线程面试题

1)什么是线程?

     线程是操作系统可以进行运算的最小的调度单位,它被包含在进程中,是进程中实际运作单位。程序员可以通过它进行多处理器编程。你可以利用多线程对密集型的运算任务进行提速。

2)线程和进程有什么区别?

     线程是进程的子集,一个进程可以有多个线程,每个线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。每个线程都拥有单独的栈内存空间来进行本地数据的存储。

3)如何在java中实现线程?

    a:继承Thread类重写run()方法,或者直接实现Runnable接口,实现run()方法。

4)Java 关键字volatile 与 synchronized 作用与区别?

 a ,volatile
    它所修饰的变量不保留拷贝,直接访问主内存中的。
           在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变 量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。 一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。

b,synchronized

    当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

         b)1、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

         b)2、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

         b)3、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

         b)4、当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

         b)5、以上规则对其它对象锁同样适用

5) 线程的生命周期有哪些?

  当在java程序中创建一个线程时.,它的状态是New,当调用start方法时候它的状态变成Runnable。线程调度器会为Runnable线程池中的线程分配CPU时间并且将他们的状态改为Running。其他的线程还有waitting,Blocked,Dead状态。

6)你对线程的优先级的理解是什么?

   每一个线程都是有优先级的,一般来说,高优先级的线程在执行的时候会具有优先权,但这依赖于线程调度的实现,这个实现是和操作系统相关的。 我们可以定义线程的优先级,但是并不能保证优先级高的就一定比优先级低的线程先执行。线程的优先级是一个int变量(从1~10),1代表最低的优先级,10表示最高的优先级。

7)什么是死锁?如何分析和避免死锁?

死锁是指两个以上线程永久阻塞的情况,这种情况产生至少要两个线程和两个以上的资源。

分析死锁,我们需要查看java线程转储,查看哪些状态为Blocked的线程和他们等待的资源。每个资源都有自己唯一的ID,用这个id我们就能找到有哪些线程已经拥有了它的对象锁。避免嵌套锁,只在有需要的地方使用锁和避免无限期等待的是避免死锁的通常办法。

8)什么是线程安全?Vector是一个线程安全类吗? 

  线程安全就是同时多个线程在执行同一段程序时候所产生的结果和单线程执行的结果是一样而其他变量值也和期望值是一样的时候线程是安全的。Veector是用同步的方法实现线程安全的,ArrayList是线程不安全的。

9) Java中如何停止一个线程?

    Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程。

10)什么是ThreadLocal?

   ThreadLocal用于创建线程本地的变量。可以使用get方法来获取他们的默认值,用set方法在线更改他们的值,ThreadLocal实例通常期望他们同线程状态关联起来的是private static 属性。

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

12)什么是线程饿死,什么是活锁?

         当所有线程阻塞,或者由于需要的资源无效而不能处理,不存在非阻塞线程使资源可用。

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

        b,当所有线程卡在无限循环中。

13)什么是Java Timer类?如何创建一个有特定时间间隔的任务?

        java.util.Timer是一个工具类,可以用于安排一个线程在未来的某个特定时间执行。Timer类可以用安排一次性任务或者周期任务。

        java.util.TimerTask是一个实现了Runnable接口的抽象类,我们需要去继承这个类来创建我们自己的定时任务并使用Timer去安排它的执行。

14)Java中的同步集合与并发集合有什么区别?

        同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。

        在Java1.5之前程序员们只有同步集合来用且在多线程并发的时候会导致争用,阻碍了系统的扩展性。

        Java5介绍了并发集合像ConcurrentHashMap,不仅提供线程安全还用锁分离和    内部分区等现代技术提高了可扩展性。

15)同步方法和同步块,哪个是更好的选择?

        同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。

16)什么是线程池? 为什么要使用它?

        创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。

        为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。

        从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。

17)Java中invokeAndWait 和 invokeLater有什么区别?

        这两个方法是Swing API 提供给Java开发者用来从当前线程而不是事件派发线程更新GUI组件用的。InvokeAndWait()同步更新GUI组件,比如一个进度条,一旦进度更新了,进度条也要做出相应改变。如果进度被多个线程跟踪,那么就调用invokeAndWait()方法请求事件派发线程对组件进行相应更新。而invokeLater()方法是异步调用更新组件的。

18)多线程中的忙循环是什么?

        忙循环就是程序员用循环让一个线程等待,不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存。

        在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存。为了避免重建缓存和减少等待重建的时间就可以使用它了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值