一、创建一个不可变类(即final类)需要满足哪些条件?

1、将类声明为final,所以它不能被继承;

2、将所有的成员声明为私有的,这样就不允许直接访问这些成员;

3、对变量不要提供setter方法;

4、将所有可变的成员声明为final,这样只能对它们赋值一次;

5、通过构造器初始化所有成员,进行深拷贝(deep copy);

6、在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝;

二、 什么是线程?什么是进程?以及他们之间的关系

        *进程是指一段程序的运行过程,是资源分配的基本单位,

        *线程是CPU独立运行和调度的基本单位,程序执行的最小单位

两者之间的联系:都是操作系统程序运行的基本单元

两者的区别:

(1)地址空间:进程之间的地址空间独立,线程共享本进程的地址空间

(2)资源拥有:进城之间资源独立,线程之间共享所属进程的资源,如:内存,CPU,IO等(线程有自己的堆和栈)

(3)执行过程:每个进程都有一个程序执行入口;线程是不能独立执行的,必须依存在进程,由程序的多线程机制控制

(4)健壮性:一个进程奔溃不会影响其他进程的执行,一个线程奔溃会导致进程的奔溃

(5)通信:进程间通信CPI,线程间可以直接读写进程数据段(共享空间)进行通信,但是需要线程的同步和互斥手段,以保证数据一致性

(6)调度和切换:线程上下文切换比进程上下文切换要快很多

三、start()和run()的区别?

Start()是启动一个线程(不是立即执行,而是使线程变为可运行态),run()是执行当前线程的方法。调用start()才能实现多线程

四、sleep()和wait()的区别?

      Sleep()是将当前线程阻塞,暂停程序,让出CPU,但不释放锁,无法执行同步方法,指定时间到了若无比它优先级高的线程执行就会恢复运行态,否则需等待

      Wait()是让线程进入等待状态,线程会释放锁,其他线程可以调用其同步方法,只有调用notify()方法后本线程才能进入锁定池准备

五、Sleep()和yield()的区别?

执行sleep()的线程时间未到是不能恢复执行态的,时间确定,较低优先级的线程有机会执行

而yield()有可能从可执行态又马上被执行,时间不定,只让给高优先级线程执行

六、解决线程不安全风险的办法:

  • 不在线程中共享该状态变量,可以将变量封装到方法中。
  • 将状态变量修改为不可变的变量(final)。
  • 访问状态变量时使用同步策略。
  • 使用原子变量类。

七、什么是线程同步?

就是线程发出一个功能调用时,在没有得到结果之前,该调用就不会返回,其他线程也不能调用该方法。

八、解释一下什么是死锁?死锁产生的原因?死锁产生的条件?

死锁是指两个线程A,B争夺同一资源s,线程A开始执行,线程A需要用到线程B执行完后的结果,这时线程A因需等待B的结果而进入阻塞状态,线程B开始运行,但却无法获取资源s,线程B也进入阻塞状态,此时两个线程处于相持状态,即死锁

九、为什么wait, notify 和 notifyAll这些方法不在thread类里面?

首先需要明白wait(),notify()之间的等待和唤醒操作是通过什么联系起来的,对象的同步锁,唤醒线程只有在获取对象的同步锁才能调用notify进行唤醒操作,同步锁是对象锁持有,并且每个对象只有一个,所以将这些方法放在Object对象中,而不是Thread

十、如何避免死锁?

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。

十一、怎么消除死锁?

(1)系统重新启动,代价有些大;(2)撤销进程,剥夺资源(3)进程回退策略

10-06 19:29