在此总结下自己在面试过程中面试官问的问题,以便于以后查阅:
1.谈谈你对java中hashMap的认识。
hashMap是java中自带的一个类,其作用为存储key-value形式的数据,key、value都可为泛型。其key值允许有一个有null,其value值可为null。hashMap的初始size为16,负载因子为0.75,如果数据的个数超过16 * 0.75时就会自动进行扩容操作。
hashMap的查找时间复杂度理想情况是O(1),但在日常业务中可能会出现哈希碰撞。hash碰撞的意思是两个不同的key在经过hash()之后得到了一样的hashCode,这时候hashMap的处理方式是将其放在该hashCode对应的bocket中,而这两个元素就已链表的形式凭借在一起,这更进一步的印证了hashMap数组 + 双向列表的结构。
在取值的时候也是一样,先根据hashCode定位到指定的bocket,如果有hash冲突再用equals()方法来比较key从而取到目标的key-value。
1.7和1.8的区别是1.8在1.7的基础上将链表结构在满足一定条件下修改为红黑树的结构,一旦这条件不满足红又会自动调整为链表结构。
2.你对多线程了解吗?谈谈线程的几个状态。
首先我们点进入thread里面,里面有线程的state
* <ul>
* <li>{@link #NEW}<br>
* A thread that has not yet started is in this state.
* </li>
* <li>{@link #RUNNABLE}<br>
* A thread executing in the Java virtual machine is in this state.
* </li>
* <li>{@link #BLOCKED}<br>
* A thread that is blocked waiting for a monitor lock
* is in this state.
* </li>
* <li>{@link #WAITING}<br>
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* </li>
* <li>{@link #TIMED_WAITING}<br>
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* </li>
* <li>{@link #TERMINATED}<br>
* A thread that has exited is in this state.
* </li>
* </ul>
NEW:新建状态,刚刚创建线程,此时线程并没有运行。
RUNNABLE:运行状态,此时的线程在Java虚拟机里面运行。
BLOCKED:阻塞状态,此时线程进入等待状态,放弃了CPU的使用权。
WAITING:等待状态,线程处于等待状态。
TIMED_WAITING:等待超时状态,超时以后自动返回。
TERMINATED:线程终止状态。
这里有一个需要注意的地方,如果是继承Thread的话,启动了thread.start(),此时线程并没用处于运行状态,当cpu分给线程资源的时候才算是真正的出入执行状态。
3.我想顺序输出A.B.C三个线程,该如何处理呢?
(1).如果是使用继承Thread,那么直接使用其中自带的一个方法join();
如下:
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
thread.join()是被final and synchronized 修饰的,因此如果线程如果要保持相关顺序行的话直接使用join()方法便能保证!如果不设置millis,则后面的thread就会一直等待,知道前面的thread执行完成才能够执行。如果设置了millis的话,那么在执行时间等于这个值之后,就会开始执行下一个线程。
Demo:
public class Demo {
public static void main(String[] args) {
for(int i = 0;i < 100;i ++){
Thread t3 = new NewThread("线程3");
Thread t1 = new NewThread("线程1");
Thread t2 = new NewThread("线程2");
try{
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
}catch (Exception e){
System.out.println(e);
}
}
}
}
4.volatile关键字的作用是什么?
volatile是一个类型修饰符,其修饰的对象在多线程操作下保证了对象的可见性。在编译器和处理器对class文件进行编译或者预处理的时候,为了提高效率往往会多指令进行重排序。使用了volatile关键字修饰之后就禁止对指令进行重排序,这便是volatile的另一个特性:有序性。如果是在单个线程的读/写下,能够保证其原子性,但是如果是i++这种形式下便无法保证其原子性。