机会是留给有准备的人!
-
简单说下什么是跨平台?
由于各种操作系统指令集不是完全一致的,所有在操作系统之上加个虚拟机可以来提供统一接口,屏蔽系统之间的差异。 -
java有几种基本数据类型
数据类型 字节 默认值 byte 1 0 short 2 0 int 4 0 long 8 0 float 4 0.0f double 8 0.0d char 2 '\u0000' boolean 4 false -
ArratList和LinkedList区别
ArrayList是基于动态数组的数据结构,LinkedList是基于链表的数据结构。
对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。
对于新增和删除add和remove,LinkedList优于ArrayList,因为ArrayList要移动数据。 -
ConncurrentModificationException异常出现的原因
public class Test{ public static void main(String[] args){ ArrayList<Integer> list = new ArrayList<Integer>(); list.add(2); Iterator<Integer> ite = list.iterator(); while(ite.hasNext()){ Integer integer = ite.next(); if(integer == 2){ list.remove(integer); } } } }
执行上段代码是有问题的,会抛出
ConcurrentModification
异常。
原因:调用list.remove()方法导致modCount和expectedModeCount的值不一致。final void checkForComodication(){ if(modCount != expectedModCount throw new ConcurrentModification(); }
解决方法:在迭代器中如果要删除元素的话,需要调用Iterator类的remove方法。
public class Test{ public static void main(String[] args){ ArrayList<Integer> list = new ArrayList<Integer>(); list.add(2); Iterator<Integer> ite = list.iterator(); while(ite.hasNext()){ Integer integer = ite.next(); if(integer == 2){ ite.remove();//注意这个地方 } } } }
-
String、StringBuffer和StringBuilder区别
- 数据可变和不可变
String
底层使用一个不可变的字符数组private final char value[];所以它内容不可变;
StringBuffer
和StringBuilder
都继承了AbstractStringBuilder
底层使用的是可变字符数组:char[] value
; - 线程安全
StringBuilder
是线程不安全的,效率较高;而StringBuffer是线程安全的,效率较低。
通过他们的append()
方法来看,StringBuffer
是有同步锁,而StringBuilder没有:
@Override public sychronized StringBuffer append(Object obj){ toStringCache = null; super.append(String.valueOf(obj)); return this; } @Override public StringBuilder append(String str){ super.append(str); return this; }
- 相同点
StringBuilder
与StringBuffer
有公共父类`AbstractStringBuilder'。
最后,操作可变字符速度:
StringBuilder > StringBuffer > String
。 - 数据可变和不可变
-
HashMap和HashTable、ConcurrentHashMap区别?
相同点:
1.HashMap和HashTable都实现Map接口
2.都可以存储key-value数据
不同点:
1.HashMap可以将null作为key或value,HashTable不可以。
2.HashMap是线程不安全,效率高,HashTable是线程安全,效率低。
3.HashMap的迭代器(Iterator)是fail-fast迭代器,而HashTable的迭代器(enumerator)不是fail-fast。fail-fast:就是就快的时间能把错误抛出而不是让程序执行。
如何保证线程安全又效率高?
Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
我们能否让HashMap同步?
HashMap可以通过下面的语句进行同步:
Map m = Collections.sychronizeMap(hashMap);
-
线程创建方式
- 继承Thread类,作为线程对象存在(继承Thread对象)
public class CreatThreadDemo1 extends Thread{ /** * 构造方法: 继承父类方法的Thread(String name);方法 * @param name */ public CreatThreadDemo1(String name){ super(name); } @Override public void run() { while (!interrupted()){ System.out.println(getName()+"线程执行了..."); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { CreatThreadDemo1 d1 = new CreatThreadDemo1("first"); CreatThreadDemo1 d2 = new CreatThreadDemo1("second"); d1.start(); d2.start(); d1.interrupt(); //中断第一个线程 } }
常规方法,不多做介绍了,interrupted方法,是来判断该线程是否被中断。(终止线程不允许用stop方法,该方法不会施放占用的资源。所以我们在设计程序的时候,要按照中断线程的思维去设计,就像上面的代码一样)。
2. 实现runnable接口作为线程任务存在public class CreatThreadDemo2 implements Runnable { @Override public void run() { while (true){ System.out.println("线程执行了..."); } } public static void main(String[] args) { //将线程任务传给线程对象 Thread thread = new Thread(new CreatThreadDemo2()); //启动线程 thread.start(); } }
Runnable 只是来修饰线程所执行的任务,它不是一个线程对象。想要启动Runnable对象,必须将它放到一个线程对象里。
3. 匿名内部类创建线程对象public class CreatThreadDemo3 extends Thread{ public static void main(String[] args) { //创建无参线程对象 new Thread(){ @Override public void run() { System.out.println("线程执行了..."); } }.start(); //创建带线程任务的线程对象 new Thread(new Runnable() { @Override public void run() { System.out.println("线程执行了..."); } }).start(); //创建带线程任务并且重写run方法的线程对象 new Thread(new Runnable() { @Override public void run() { System.out.println("runnable run 线程执行了..."); } }){ @Override public void run() { System.out.println("override run 线程执行了..."); } }.start(); } }
创建带线程任务并且重写run方法的线程对象中,为什么只运行了Thread的run方法。我们看看Thread类的源码:
public class Thread implements Runnable{……}
;
4.创建带返回值的线程public class CreatThreadDemo4 implements Callable { public static void main(String[] args) throws ExecutionException, InterruptedException { CreatThreadDemo4 demo4 = new CreatThreadDemo4(); FutureTask<Integer> task = new FutureTask<Integer>(demo4); //FutureTask最终实现的是runnable接口 Thread thread = new Thread(task); thread.start(); System.out.println("我可以在这里做点别的业务逻辑...因为FutureTask是提前完成任务"); //拿出线程执行的返回值 Integer result = task.get(); System.out.println("线程中运算的结果为:"+result); } //重写Callable接口的call方法 @Override public Object call() throws Exception { int result = 1; System.out.println("业务逻辑计算中..."); Thread.sleep(3000); return result; } }
Callable接口介绍:
public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
返回指定泛型的call方法。然后调用FutureTask对象的get方法得道call方法的返回值。
5. 定时器Timerpublic class CreatThreadDemo5 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("定时器线程执行了..."); } },0,1000); //延迟0,周期1s } }
- 线程池创建线程
public class CreatThreadDemo6 { public static void main(String[] args) { //创建一个具有10个线程的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(10); long threadpoolUseTime = System.currentTimeMillis(); for (int i = 0;i<10;i++){ threadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"线程执行了..."); } }); } long threadpoolUseTime1 = System.currentTimeMillis(); System.out.println("多线程用时"+(threadpoolUseTime1-threadpoolUseTime)); //销毁线程池 threadPool.shutdown(); threadpoolUseTime = System.currentTimeMillis(); } }
7.利用java8新特性 stream 实现并发
public class CreatThreadDemo7 { public static void main(String[] args) { List<Integer> values = Arrays.asList(10,20,30,40); //parallel 平行的,并行的 int result = values.parallelStream().mapToInt(p -> p*2).sum(); System.out.println(result); //怎么证明它是并发处理呢 values.parallelStream().forEach(p-> System.out.println(p)); } }