1.集合分类
两个大类:Collection(接口) 和Map(接口)
Collection下有三个接口 List,Set,Queue
List接口有三个实现类:arrayList,LinkList,vector(线程安全 synchronizer 锁方法,基本不用)
Map接口有两个实现类:HashMap和HashTable(线程安全 synchronizer 锁方法 基本不用)
arrayList和LinkList的区别:
arrayList基于动态数组结构;linkList是基于链表结构
arrayList 查询快
linkList 新增删除快,只需要移动指针
HashMap 和 Hashtable 的区别?
HashMap 允许空键值,Hashtable 不允许;
HashMap 继承自 AbstractMap,Hashtable 继承自 Dictionary 类,两者都实现了 Map 接口; HashMap 的方法不是同步的,Hashtable 的方法是同步的。
HashMap的实现原理
通过put和get存储和获取对象,存储对象时,我们将K/V传给put方法时,它调用hashcode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量。获取对象时,我们将K传递给get,他调用hashcode计算hash从而得到bucket位置,并进一步调用equals()方法确认键值对。
如果需要更具体的信息:https://blog.csdn.net/Woo_home/article/details/103146845
集合的线程安全如何实现
通过集合工具Collections提供的同步方法
1.Collections.synchronizedList
2.Collections.synchronizedSet
3.Collections.synchronizedMap
遍历list的几种方法
List<String> list = new ArrayList<>();
第一种:for (String id : list) {}
第二种:for (int i = 0; i < list.size(); i++) {}
第三种:Iterator iterator = list.iterator(); while (iterator.hasNext()){ String a= (String) iterator.next();}
遍历Map的几种方法
Map<String, String> map = new HashMap<>();
第一种:for (String key : map.keySet()) { String value = map.get(key); }
第二种:for (Map.Entry entry : map.entrySet()) { String key = (String) entry.getKey(); String value = (String) entry.getValue(); }
2.线程
java线程的五种状态
新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
-
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
-
2.同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
-
3.其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
线程同步的几种方式
1、synchronized修饰
2、volatile实现同步(只能保证可见性,不能保证原子性)
3、使用局部变量ThreadLocal
4、使用原子类(AtomicInteger、AtomicBoolean……)
5、使用Lock
6、使用容器类(BlockingQueue、ConcurrentHashMap)
实现线程的几种方式
- 继承Thread类创建线程
- 实现Runnable接口创建线程
- 实现Callable接口创建新线程(可用Future返回结果)
ThreadLocal
提供线程内部的局部变量,这些变量在多线程环境下访问(get/set)时能保证与其它线程里的变量相对独立
锁
锁是什么
锁主要用来实现资源共享的同步。只有获取到了锁才能访问该同步代码,否则等待其他线程使用结束释放锁
有哪几种锁?
synchronize和Lock
synchronize: 可以放在方法前面;也可以放在代码块前面,但需要指定上锁的对象。
Lock:拥有synchronize相同的语义,但是添加一些其他特性,如中断锁等候和定时锁等候,所以可以使用lock代替synchronize,但需要在finally中手动释放。
synchronize和Lock两者的区别
性能不一致:资源竞争激励的情况下,lock性能会比synchronize好,竞争不激励的情况下,synchronize比lock性能好。
锁机制不一样:synchronize是在JVM层面实现的,系统会监控锁的释放与否。lock是代码实现的,需要手动释放,在finally块中释放。可以采用非阻塞的方式获取锁。
用法不一样:synchronize可以用在代码块上,方法上。lock通过代码实现,有更精确的线程语义
乐观锁和悲观锁的理解及如何实现,有哪些实现方式?
乐观锁,每次操作时不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止
悲观锁是会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。
乐观锁可以使用volatile+CAS原语实现,带参数版本来避免ABA问题,在读取和替换的时候进行判定版本是否一致
悲观锁可以使用synchronize的以及Lock