一、COllections.sort内部原理
Collection.sort()排序通过泛化实现对所有类型的排序,对于基础类型如int,string,按照字符表,数字大小排序。对于自定义类型,通过实现Comparable接口,重写comparableTo()方法自定义比较大小的方式。也可以使用Comparator外比较器,Comparable接口的方式比实现Comparator接口的耦合性要强一些。
Collection.sort内部调用的是Arrays.sort方法,对于Arrays类,有两个sort方法,sort(Object)和sort(int),前者使用归并排序,后者使用快排。
import java.util.*;
class xd{
int a;
int b;
xd(int a,int b){
this.a=a;
this.b=b;
}
}
public class Main(){
public static void main(String[] args){
xd a=new xd(2,3);
xd b=new xd(4,1);
xd c=new xd(1,2);
ArrayList<xd> list=new ArrayList<>();
array.add(a);
array.add(b);
array.add(c);
Collections.sort(array,new Comparator<xd>(){
@Override
public int compare(xd o1,xd o2){
if(o1.a>o2.a)
return 1;
else if(o1.a<o2.a)
return -1;
return 0;
}
});
for(int i=0;i<array.size();i++)
System.out.println(array.get(i).a);
for(int i=0;i<array.size();i++)
System.out.println(array.get(i).b);
}
}
二、TreeMap和TreeSet
TreeMap和TreeSet都是Java Collection Framework的两个重要成员,其中TreeMap实现了Map接口,TreeSet实现了set接口。TreeSet底层是通过TreeMap来实现的。二者的实现方式完全一样,而TreeMap的实现就是红黑树算法。
- TreeMap和TreeSet都是有序的集合,它们存储的值都是排好序的
- TreeMap和TreeSet都是非同步的集合,他们不能再多线程之间共享,不过可以使用Collections.synchronizedMap()来实现同步
- 运行速度都比Hash集合慢,时间复杂度为O(logN)。而HashMap/HashSet则为O(1)。
- TreeSet实现了Set接口而TreeMap实现了Map接口。
- TreeSet只存储一个对象,而TreeMap存储两个对象key和Value。
- TreeSet中不能有重复对象,而TreeMap可以有重复对象。
三、集合和有序集合有什么区别?
有序集合里的元素可以根据key或index访问,有序集合在属性的增加、删除、修改中拥有较好的性能。
无序集合里的元素只能遍历。
- 无序集:set
- 有序集:List
凡是实现set的AbstractSet、CopyOnWriteArraySet、EnumSet、HashSet、LinkedHashSet、TreeSet都是无序的
凡是实现List的AbstractList、ArrayList、LinkedList、Stack、Vector都是有序的
- Map:Map可以根据key来访问,从这个角度将,Map也是有序的
四、Set是无序的,怎么保证有序
Set是无序的,但是TreeSet可以保证有序。
五、Java集合框架
Java集合大致可以分为Set、List、Queue和Map四种体系。其中Set代表无序,不可重复的集合。List代表有序,可以重复的集合。Map代表映射关系的集合。Java5又增加了Queue体系,代表一种队列集合实现。
Java集合和数组的区别:
数组元素在初始化时指定,意味着只能保存定长的数据。而集合可以保存数量不确定的数据。数组元素既可以保存基本类型的值,也可以是对象。集合里只能保存对象。基本数据类型要转换成对应的包装类才能放入集合类中。
Java集合类之间的继承关系:Java的集合类主要由两个接口派生而出:Collection和Map。
Map实现类用于保存具有映射关系的数据。Map保存的每项数据都是key-value对,也就是由key和value两个值组成。
六、Iterator和ListIterator的区别是什么
Iterator可以用来遍历Set和List集合,但是ListIterator只能遍历List。Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
七、快速失败和安全失败的区别是什么
Iterator的安全失败是基于对底层集合做拷贝,它不受源集合上修改的影响。Java.concurrent包下面的所有类都是安全失败的。而快速失败受到源集合修改的影响,Java.util包下面的所有集合类都是快速失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器不会抛出此异常。
八、Java哪些类是线程安全的
Vector:比ArrayList多了个同步机制(Synchronized)
HashTable:HashMap的线程安全版本
Stack:Stack也是线程安全的,继承与Vector
九、Volatile和synchronized区别
- 加锁机制既可以保证可见性又可以保证原子性,而volatile只能确保可见性,不能保证原子性
- volatile不会进行加锁操作。volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作。也就不会使线程阻塞,因此volatile是一种比Synchronized更轻量级的同步机制。
- volatile不如synchronized安全。
十、Volatile
volatile关键字保证了内存可见性,防止指令重排序。volatile并不保证原子性。
- volatile保证内存可见性的原理是每次访问变量时都会进行一次刷新,因此每次访问都是主内存中最新的版本。所以volatile关键字的作用之一就是保证变量修改的实时可见性。
- 由于volatile屏蔽掉了JVM中必要的代码优化,所以在效率上比较低。
十一、Java编写一个会导致死锁的程序
public static void main(String[] args){
final Object a=new Object();
final Object b=new Object();
Thread threadA=new Thread(new Runnable(){
@Override
public void run(){
synchronized(a){
try{
Thread.sleep(5000);
synchronized(b){
Thread.sleep(1000);
System.out.println("锁住b");
}
}
catch(Exception e){
e.printStackTrace();
}
}
});
Thread threadB=new Thread(new Runnable(){
@Override
public void run(){
synchronized(b){
try{
Thread.sleep(5000);
Synchroninzed(a){
Thread.sleep(1000);
System.out.println(“锁住A”);
}catch(Exception e){
e.printStackTrace();
}
});
ThreadA.start();
ThreadB.start();
}
十二、自旋锁、偏向锁、轻量级锁、重量级锁
阻塞操作会导致在用户态和内核态之间切换,严重影响性能。在很多场景下,同步资源的锁定时间很短,为了这一小段时间去切换线程可能会偿失,可以让线程“稍微等待一会”,这就是自旋锁。
无锁、偏向锁、轻量级锁、重量级锁都是针对synchronized的。synchronized是悲观锁,在操作同步资源之前需要给同步资源加锁,这把锁就存在Java对象头里面。
一个线程访问:在大多数情况下,锁总是由一个线程获得,不存在多线程竞争,所以出现了偏向锁。其目标就是在只有一个线程执行同步代码块的情况下能够提高性能
轻量级锁:两个线程交替访问,锁升级,升级为轻量级锁。
重量级锁:多个线程访问,竞争激烈,升级了重量级锁。
十三、