1、Log4j日志有几个级别?
由低到高:debug、info、wran、error
2、3*0.1 == 0.3 将会返回什么?true 还是 false?
false,因为有些浮点数不能完全精确的表示出来。
3、什么是内存屏障?
内存屏障,也叫内存栅栏,是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。
4、写一段代码在遍历 ArrayList 时移除一个元素?
该问题的关键在于面试者使用的是 ArrayList 的 remove() 还是 Iterator 的 remove()方法。这有一段示例代码,是使用正确的方式来实现在遍历的过程中移除元素,而不会出现 ConcurrentModificationException 异常的示例代码。
5、AQS支持两种同步方式:
1、 独占式
2、 共享式
这样方便使用者实现不同类型的同步组件,独占式如ReentrantLock,共享式如Semaphore,CountDownLatch,组合式的如ReentrantReadWriteLock。总之,AQS为使用提供了底层支撑,如何组装实现,使用者可以自由发挥。
6、Int与integer的区别
Integer是int的包装类型。
Int的默认值是0,integer的默认值是null
7、在 Java 程序中怎么保证多线程的运行安全?
出现线程安全问题的原因一般都是三个原因:
1、 线程切换带来的原子性问题 解决办法:使用多线程之间同步synchronized或使用锁(lock)。
2、 缓存导致的可见性问题 解决办法:synchronized、volatile、LOCK,可以解决可见性问题
3、 编译优化带来的有序性问题 解决办法:Happens-Before 规则可以解决有序性问题
8、如何选择单例创建方式
如果不需要延迟加载单例,可以使用枚举或者饿汉式,相对来说枚举性好于饿汉式。 如果需要延迟加载,可以使用静态内部类或者懒汉式,相对来说静态内部类好于懒韩式。 最好使用饿汉式
- 代码演示
主要使用懒汉和懒汉式
1、 饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。
2、 懒汉式: 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
3、 静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
4、 枚举单例: 使用枚举实现单例模式 优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞, 缺点没有延迟加载。
5、 双重检测锁方式 (因为JVM本质重排序的原因,可能会初始化多次,不推荐使用)
- 饿汉式
饿汉式:
类初始化时,会立即加载该对象,线程天生安全,调用效率高。
package com.lijie;
//饿汉式
public class Demo1 {
// 类初始化时,会立即加载该对象,线程安全,调用效率高
private static Demo1 demo1 = new Demo1();
private Demo1() {
System.out.println("私有Demo1构造参数初始化");
}
public static Demo1 getInstance() {
return demo1;
}
public static void main(String[] args) {
Demo1 s1 = Demo1.getInstance();
Demo1 s2 = Demo1.getInstance();
System.out.println(s1 == s2);
}
}
- 懒汉式
懒汉式:
类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
package com.lijie;
//懒汉式
public class Demo2 {
//类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象。
private static Demo2 demo2;
private Demo2() {
System.out.println("私有Demo2构造参数初始化");
}
public synchronized static Demo2 getInstance() {
if (demo2 == null) {
demo2 = new Demo2();
}
return demo2;
}
public static void main(String[] args) {
Demo2 s1 = Demo2.getInstance();
Demo2 s2 = Demo2.getInstance();
System.out.println(s1 == s2);
}
}
- 静态内部类
静态内部方式:
结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
package com.lijie;
// 静态内部类方式
public class Demo3 {
private Demo3() {
System.out.println("私有Demo3构造参数初始化");
}
public static class SingletonClassInstance {
private static final Demo3 DEMO_3 = new Demo3();
}
// 方法没有同步
public static Demo3 getInstance() {
return SingletonClassInstance.DEMO_3;
}
public static void main(String[] args) {
Demo3 s1 = Demo3.getInstance();
Demo3 s2 = Demo3.getInstance();
System.out.println(s1 == s2);
}
}
- 枚举单例式
枚举单例:
使用枚举实现单例模式 优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞, 缺点没有延迟加载。
package com.lijie;
//使用枚举实现单例模式 优点:实现简单、枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞 缺点没有延迟加载
public class Demo4 {
public static Demo4 getInstance() {
return Demo.INSTANCE.getInstance();
}
public static void main(String[] args) {
Demo4 s1 = Demo4.getInstance();
Demo4 s2 = Demo4.getInstance();
System.out.println(s1 == s2);
}
//定义枚举
private static enum Demo {
INSTANCE;
// 枚举元素为单例
private Demo4 demo4;
private Demo() {
System.out.println("枚举Demo私有构造参数");
demo4 = new Demo4();
}
public Demo4 getInstance() {
return demo4;
}
}
}
- 双重检测锁方式
双重检测锁方式
因为JVM本质重排序的原因,可能会初始化多次,不推荐使用
package com.lijie;
//双重检测锁方式
public class Demo5 {
private static Demo5 demo5;
private Demo5() {
System.out.println("私有Demo4构造参数初始化");
}
public static Demo5 getInstance() {
if (demo5 == null) {
synchronized (Demo5.class) {
if (demo5 == null) {
demo5 = new Demo5();
}
}
}
return demo5;
}
public static void main(String[] args) {
Demo5 s1 = Demo5.getInstance();
Demo5 s2 = Demo5.getInstance();
System.out.println(s1 == s2);
}
}
9、Java中的继承是单继承还是多继承
Java中既有单继承,又有多继承。对于Java类来说只能有一个父类,对于接口来说可以同时继承多个接口
10、类与对象的关系?
类是对象的抽象,对象是类的具体,类是对象的模板,对象是类的实例