2019年Java面试题基础系列228道java
第一篇更新1~20题的答案解析
程序员
2019年Java面试题基础系列228道(1),快看看哪些你还不会?web
第二篇更新21~50题答案解析面试
2019年Java面试题基础系列228道(2),查漏补缺!数组
第三篇更新51~95题答案解析
缓存
2019年Java面试题基础系列228道(3),查漏补缺!
安全
Java 面试题(二)服务器
一、Java 中能建立 volatile 数组吗?多线程
二、volatile 能使得一个非原子操做变成原子操做吗?app
三、volatile 修饰符的有过什么实践?
四、volatile 类型变量提供什么保证?
五、10 个线程和 2 个线程的同步代码,哪一个更容易写?
六、你是如何调用 wait()方法的?使用 if 块仍是循环?为何?
八、什么是 Busy spin?咱们为何要使用它?
九、Java 中怎么获取一份线程 dump 文件?
十、Swing 是线程安全的?
十一、什么是线程局部变量?
十二、用 wait-notify 写一段代码来解决生产者-消费者问题?
1三、用 Java 写一个线程安全的单例模式(Singleton)?
1四、Java 中 sleep 方法和 wait 方法的区别?
1五、什么是不可变对象(immutable object)?Java 中怎么建立一个不可变对象?
1六、咱们能建立一个包含可变对象的不可变对象吗?
1七、Java 中应该使用什么数据类型来表明价格?
1八、怎么将 byte 转换为 String?
1九、Java 中怎样将 bytes 转换为 long 类型?
20、咱们能将 int 强制转换为 byte 类型的变量吗?若是该值大于byte 类型的范围,将会出现什么现象?
本次更新Java 面试题(二)的1~20题答案
一、Java 中能建立 volatile 数组吗?
能,Java 中能够建立 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组。个人意思是,若是改变引用指向的数组,将会受到 volatile 的保护,可是若是多个线程同时改变数组的元素,volatile 标示符就不能起到以前的保护做用了。
二、volatile 能使得一个非原子操做变成原子操做吗?
一个典型的例子是在类中有一个 long 类型的成员变量。若是你知道该成员变量会被多个线程访问,如计数器、价格等,你最好是将其设置为 volatile。为何?由于 Java 中读取 long 类型变量不是原子的,须要分红两步,若是一个线程正在修改该 long 变量的值,另外一个线程可能只能看到该值的一半(前 32 位)。可是对一个 volatile 型的 long 或 double 变量的读写是原子。
三、volatile 修饰符的有过什么实践?
一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写。double 和 long 都是 64 位宽,所以对这两种类型的读是分为两部分的,第一次读取第一个 32 位,而后再读剩下的 32 位,这个过程不是原子的,但 Java 中volatile 型的 long 或 double 变量的读写是原子的。volatile 修复符的另外一个做用是提供内存屏障(memory barrier),例如在分布式框架中的应用。简单的说,就是当你写一个 volatile 变量以前,Java 内存模型会插入一个写屏障(writebarrier),读一个 volatile 变量以前,会插入一个读屏障(read barrier)。意思就是说,在你写一个 volatile 域时,能保证任何线程都能看到你写的值,同时,在写以前,也能保证任何数值的更新对全部线程是可见的,由于内存屏障会将其余全部写的值更新到缓存。
四、volatile 类型变量提供什么保证?
volatile 变量提供顺序和可见性保证,例如,JVM 或者 JIT 为了得到更好的性能会对语句重排序,可是 volatile 类型变量即便在没有同步块的状况下赋值也不会与其余语句重排序。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其余线程是可见的。某些状况下,volatile 还能提供原子性,如读 64 位数据类型,像 long 和 double 都不是原子的,但 volatile 类型的 double 和long 就是原子的。
五、10 个线程和 2 个线程的同步代码,哪一个更容易写?
从写代码的角度来讲,二者的复杂度是相同的,由于同步代码与线程数量是相互独立的。可是同步策略的选择依赖于线程的数量,由于越多的线程意味着更大的竞争,因此你须要利用同步技术,如锁分离,这要求更复杂的代码和专业知识。
六、你是如何调用 wait()方法的?使用 if 块仍是循环?为何?
wait() 方法应该在循环调用,由于当线程获取到 CPU 开始执行的时候,其余条件可能尚未知足,因此在处理前,循环检测条件是否知足会更好。下面是一段标准的使用 wait 和 notify 方法的代码:
// The standard idiom for using the wait methodsynchronized (obj) { while (condition does not hold) obj.wait(); // (Releases lock, and reacquires on wakeup) ... // Perform action appropriate to condition}
七、什么是多线程环境下的伪共享(false sharing)?
伪共享是多线程系统(每一个处理器有本身的局部缓存)中一个众所周知的性能问题。伪共享发生在不一样处理器的上的线程对变量的修改依赖于相同的缓存行。
八、什么是 Busy spin?咱们为何要使用它?
Busy spin 是一种在不释放 CPU 的基础上等待事件的技术。它常常用于避免丢失 CPU 缓存中的数据(若是线程先暂停,以后在其余 CPU 上运行就会丢失)。因此,若是你的工做要求低延迟,而且你的线程目前没有任何顺序,这样你就能够经过循环检测队列中的新消息来代替调用 sleep() 或 wait() 方法。它惟一的好处就是你只需等待很短的时间,如几微秒或几纳秒。LMAX 分布式框架是一个高性能线程间通讯的库,该库有一个 BusySpinWaitStrategy 类就是基于这个概念实现的,使用 busy spin 循环 EventProcessors 等待屏障。
九、Java 中怎么获取一份线程 dump 文件?
在 Linux 下,你能够经过命令 kill -3 PID (Java 进程的进程 ID)来获取 Java应用的 dump 文件。在 Windows 下,你能够按下 Ctrl + Break 来获取。这样 JVM 就会将线程的 dump 文件打印到标准输出或错误文件中,它可能打印在控制台或者日志文件中,具体位置依赖应用的配置。若是你使用 Tomcat。
十、Swing 是线程安全的?
不是,Swing 不是线程安全的。你不能经过任何线程来更新 Swing 组件,如JTable、JList 或 JPanel,事实上,它们只能经过 GUI 或 AWT 线程来更新。这就是为何 Swing供 invokeAndWait() 和 invokeLater() 方法来获取其余线程的 GUI 更新请求。这些方法将更新请求放入 AWT 的线程队列中,能够一直等待,也能够经过异步更新直接返回结果。你也能够在参考答案中查看和学习到更详细的内容。
十一、什么是线程局部变量?
线程局部变量是局限于线程内部的变量,属于线程自身全部,不在多个线程间共享。Java 提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式。可是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别当心,在这种状况下,工做线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工做完成后没有释放,Java 应用就存在内存泄露的风险。
十二、用 wait-notify 写一段代码来解决生产者-消费者问题?
只要记住在同步块中调用 wait() 和 notify()方 法 ,若是阻塞,经过循环来测试等待条件。
1三、用 Java 写一个线程安全的单例模式(Singleton)?
一步一步建立一个线程安全的 Java 单例类。当咱们说线程安全时,意思是即便初始化是在多线程环境中,仍然能保证单个实例。Java 中,使用枚举做为单例类是最简单的方式来建立线程安全单例模式的方式。
1四、Java 中 sleep 方法和 wait 方法的区别?
虽然二者都是用来暂停当前运行的线程,可是 sleep() 实际上只是短暂停顿,由于它不会释放锁,而 wait() 意味着条件等待,这就是为何该方法要释放锁,由于只有这样,其余等待的线程才能在知足条件时获取到该锁。
1五、什么是不可变对象(immutable object)?Java 中怎么建立一个不可变对象?
不可变对象指对象一旦被建立,状态就不能再改变。任何修改都会建立一个新的对象,如 String、Integer 及其它包装类。详情参见答案,一步一步指导你在 Java中建立一个不可变的类。
1六、咱们能建立一个包含可变对象的不可变对象吗?
是的,咱们是能够建立一个包含可变对象的不可变对象的,你只须要谨慎一点,不要共享可变对象的引用就能够了,若是须要变化时,就返回原对象的一个拷贝。最多见的例子就是对象中包含一个日期对象的引用。数据类型和 Java 基础面试问题
1七、Java 中应该使用什么数据类型来表明价格?
若是不是特别关心内存和性能的话,使用 BigDecimal,不然使用预约义精度的double 类型。
1八、怎么将 byte 转换为 String?
可使用 String 接收 byte[] 参数的构造器来进行转换,须要注意的点是要使用的正确的编码,不然会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不一样。欢迎你们关注个人公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。
1九、Java 中怎样将 bytes 转换为 long 类型?
bytes[] 到数字类型的转换是个常常用到的代码,解决方式也不止一种。
java代码实现
若是不想借助任何已经有的类,彻底能够本身实现这段代码,以下:
/** * 将字节数组转为long<br> * 若是input为null,或offset指定的剩余数组长度不足8字节则抛出异常 * @param input * @param offset 起始偏移量 * @param littleEndian 输入数组是否小端模式 * @return */public static long longFrom8Bytes(byte[] input, int offset, Boolean littleEndian){ long value=0; // 循环读取每一个字节经过移位运算完成long的8个字节拼装 for (int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value;}
借助java.nio.ByteBuffer实现
java.nio.ByteBuffer 自己就有getLong,getInt,getFloat….方法,只要将byte[]转换为ByteBuffer就能够实现全部primitive类型的数据读取,参见javadoc。
/** * 利用 {@link java.nio.ByteBuffer}实现byte[]转long * @param input * @param offset * @param littleEndian 输入数组是否小端模式 * @return */public static long bytesTolong(byte[] input, int offset, Boolean littleEndian) { // 将byte[] 封装为 ByteBuffer ByteBuffer buffer = ByteBuffer.wrap(input,offset,8); if(littleEndian){ // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN) // ByteBuffer 默认为大端(BIG_ENDIAN)模式 buffer.order(ByteOrder.LITTLE_ENDIAN); } return buffer.getlong();}
借助java.io.DataInputStream实现
java.io.DataInputStream 一样提供了readLong,readLong,readLong….方法,只要将byte[]转换为DataInputStream就能够实现全部primitive类型的数据读取,参见javadoc。
20、咱们能将 int 强制转换为 byte 类型的变量吗?若是该值大于 byte 类型的范围,将会出现什么现象?
是的,咱们能够作强制转换,可是 Java 中 int 是 32 位的,而 byte 是 8 位的,因此,若是强制转化是,int 类型的高 24 位将会被丢弃,byte 类型的范围是从 -128 到 128。
最后
欢迎你们一块儿交流,喜欢文章记得关注我点个赞哟,感谢支持!