集合
- List 和 Set 区别
collection的子接口list和se
list:①,允许重复对象②,可以插入多个null元素③,有序容器
④,常用的实现类有ArrayList、LinkedList和Vector,ArrayList使用索引随意访问,而LinkedList则更适合经常从list中添加删除的场合。
set:①,不能有重复元素②,无序容器③,只能有一个null元素
④,实现类有HashSet、LinkedHashSet、TreeSet
map:①,map不是collection的子接口或实现类,是一个接口②,map的每个Entry都有两个对象,一个键一个值,键不能重复。
③,可以有多个null值,但只能有一个null键
④,实现类有HashMap、LinkedHashMap、HashTable、TreeMap
- List 和 Map 区别
- Arraylist 与 LinkedList 区别
- ArrayList 与 Vector 区别
- HashMap 和 Hashtable 的区别
1、作者不同
2、时间不同,Hashtable自java发布以来,HashMap产生于jdk1.2
3、继承的父类不同HashTable继承Dictinary类,HashMap继承AbstractMap类
4、Hashtable既不支持Null key也不支持Null value
5、HashMap中,null可以作为键,判断是否存在一个键不能使用get()方法,当职位null时get()方法返回null,应该使用containsKey()方法判断。
6、Hashtable线程安全,每个方法都加入了Synchronize方法。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
7、为了得到元素的位置,首先需要根据元素的 KEY计算出一个hash值,然后再用这个hash值来计算得到最终的位置。hash值的方法不同,Hashtable直接使用对象的hashCode,hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。
Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。
HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算
为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。当然了,为了高效,HashMap只做了一些简单的位处理。从而不至于把使用2 的幂次方带来的效率提升给抵消掉。
- HashSet 和 HashMap 区别
- HashMap 和 ConcurrentHashMap 的区别
- HashMap 的工作原理及代码实现
https://www.cnblogs.com/chengxiao/p/6059914.html
- ConcurrentHashMap 的工作原理及代码实现
https://blog.csdn.net/helei810304/article/details/79786606
线程
- 创建线程的方式及实现
https://blog.csdn.net/m0_37840000/article/details/79756932
创建线程的四种方式:
①继承Thread类,重写run方法
② 实现Runnable接口,重写run方法
③使用线程池例如用Executor框架
④使用Callable和Future创建线程
--------继承Thread方式--------------------------------------------------------------
public class MyThread extends Thread{
public void run(){//重写run方法}
}
public class Test{
public static void main(String[] args){
new MyThread().start();//启动线程
}
}
-----实现Runnable接口方式-----------------------------------------------
public class MyThread implements Runnable{
public void run(){}
}
public class test{
public static void main(String[] args){
MyThrea tt = new MyThread();
Thread thread = new Thread(tt);
thread.start();
}
}
------------------------使用Callable和Future创建线程---------------------
1】创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例(从java8开始可以直接使用Lambda表达式创建Callable对象)。
2】使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值
3】使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口)
4】调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
代码实例:
public class Main {
public static void main(String[] args){
MyThread3 th=new MyThread3();
//使用Lambda表达式创建Callable对象
//使用FutureTask类来包装Callable对象
FutureTask<Integer> future=new FutureTask<Integer>(
(Callable<Integer>)()->{
return 5;
}
);
new Thread(task,"有返回值的线程").start();//实质上还是以Callable对象来创建并启动线程
try{
System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回
}catch(Exception e){
ex.printStackTrace();
}
}
}
- sleep() 、join()、yield()有什么区别
1、sleep()
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。
例如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行;但是高优先级的线程sleep(500)后,低优先级就有机会执行了。
总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。
2、join()
join()方法使调用该方法的线程在此之前执行完毕,也就是等待该方法的线程执行完毕后再往下继续执行。注意该方法也需要捕捉异常。
3、yield()
该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。
4、wait:Object类的方法,必须放在循环体和同步代码块中,执行该方法的线程会释放锁,进入线程等待池中等待被再次唤醒(notify随机唤醒,notifyAll全部唤醒,线程结束自动唤醒)即放入锁池中竞争同步锁
- 说说 CountDownLatch 原理
- 说说 CyclicBarrier 原理
- 说说 Semaphore 原理
- 说说 Exchanger 原理
- 说说 CountDownLatch 与 CyclicBarrier 区别
- ThreadLocal 原理分析
- 讲讲线程池的实现原理
- 线程池的几种方式与使用场景
- 线程的生命周期
(1)生命周期的五种状态
新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread();
就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();
运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。
死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
自然终止:正常运行run()方法后终止
异常终止:调用stop()方法让一个线程终止运行
堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)
锁机制
- 说说线程安全问题
- volatile 实现原理
- synchronize 实现原理
- synchronized 与 lock 的区别
- CAS 乐观锁
- ABA 问题
- 乐观锁的业务场景及实现方式