1、Java 中能创建 volatile 数组吗?

能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组。我的意思是,如果改变引用指向的数组,将会受到 volatile 的保护,但是如果多个线程同时改变数组的元素,volatile 标示符就不能起到之前的保护作用了。

2、volatile 能使得一个非原子操作变成原子操作吗?

一个典型的例子是在类中有一个 long 类型的成员变量。如果你知道该成员变量会被多个线程访问,如计数器、价格等,你最好是将其设置为 volatile。为什么?因为 Java 中读取 long 类型变量不是原子的,需要分成两步,如果一个线程正在修改该 long 变量的值,另一个线程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或 double 变量的读写是原子。

3、volatile 修饰符的有过什么实践?

一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写。double 和 long 都是 64 位宽,因此对这两种类型的读是分为两部分的,第一次读取第一个 32 位,然后再读剩下的 32 位,这个过程不是原子的,但 Java 中volatile 型的 long 或 double 变量的读写是原子的。volatile 修复符的另一个作用是提供内存屏障(memory barrier),例如在分布式框架中的应用。简单的说,就是当你写一个 volatile 变量之前,Java 内存模型会插入一个写屏障(writebarrier),读一个 volatile 变量之前,会插入一个读屏障(read barrier)。意思就是说,在你写一个 volatile 域时,能保证任何线程都能看到你写的值,同时,在写之前,也能保证任何数值的更新对所有线程是可见的,因为内存屏障会将其他所有写的值更新到缓存。

4、volatile 类型变量提供什么保证?

volatile 变量提供顺序和可见性保证,例如,JVM 或者 JIT 为了获得更好的性能会对语句重排序,但是 volatile 类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。某些情况下,volatile 还能提供原子性,如读 64 位数据类型,像 long 和 double 都不是原子的,但 volatile 类型的 double 和long 就是原子的。

5、10 个线程和 2 个线程的同步代码,哪个更容易写?

从写代码的角度来说,两者的复杂度是相同的,因为同步代码与线程数量是相互独立的。但是同步策略的选择依赖于线程的数量,因为越多的线程意味着更大的竞争,所以你需要利用同步技术,如锁分离,这要求更复杂的代码和专业知识。

6、你是如何调用 wait()方法的?使用 if 块还是循环?为什么?

  wait() 方法应该在循环调用,因为当线程获取到 CPU 开始执行的时候,其他条件可能还没有满足,所以在处理前,循环检测条件是否满足会更好。下面是一段标准的使用 wait 和 notify 方法的代码:

  1. // The standard idiom for using the wait methodsynchronized (obj) {
  2. while (condition does not hold)
  3. obj.wait();
  4. // (Releases lock, and reacquires on wakeup)
  5. ... // Perform action appropriate to condition}

7、什么是多线程环境下的伪共享(false sharing)?

  伪共享是多线程系统(每个处理器有自己的局部缓存)中一个众所周知的性能问题。伪共享发生在不同处理器的上的线程对变量的修改依赖于相同的缓存行。

8、什么是 Busy spin?我们为什么要使用它?

Busy spin 是一种在不释放 CPU 的基础上等待事件的技术。它经常用于避免丢失 CPU 缓存中的数据(如果线程先暂停,之后在其他 CPU 上运行就会丢失)。所以,如果你的工作要求低延迟,并且你的线程目前没有任何顺序,这样你就可以通过循环检测队列中的新消息来代替调用 sleep() 或 wait() 方法。它唯一的好处就是你只需等待很短的时间,如几微秒或几纳秒。LMAX 分布式框架是一个高性能线程间通信的库,该库有一个 BusySpinWaitStrategy 类就是基于这个概念实现的,使用 busy spin 循环 EventProcessors 等待屏障。

9、Java 中怎么获取一份线程 dump 文件?

在 Linux 下,你可以通过命令 kill -3 PID (Java 进程的进程 ID)来获取 Java应用的 dump 文件。在 Windows 下,你可以按下 Ctrl + Break 来获取。这样 JVM 就会将线程的 dump 文件打印到标准输出或错误文件中,它可能打印在控制台或者日志文件中,具体位置依赖应用的配置。如果你使用 Tomcat。

10、Swing 是线程安全的?

不是,Swing 不是线程安全的。你不能通过任何线程来更新 Swing 组件,如JTable、JList 或 JPanel,事实上,它们只能通过 GUI 或 AWT 线程来更新。这就是为什么 Swing供 invokeAndWait() 和 invokeLater() 方法来获取其他线程的 GUI 更新请求。这些方法将更新请求放入 AWT 的线程队列中,可以一直等待,也可以通过异步更新直接返回结果。你也可以在参考答案中查看和学习到更详细的内容。

11、什么是线程局部变量?

线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java 提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。

12、用 wait-notify 写一段代码来解决生产者-消费者问题?

  只要记住在同步块中调用 wait() 和 notify()方 法 ,如果阻塞,通过循环来测试等待条件。

13、用 Java 写一个线程安全的单例模式(Singleton)?

一步一步创建一个线程安全的 Java 单例类。当我们说线程安全时,意思是即使初始化是在多线程环境中,仍然能保证单个实例。Java 中,使用枚举作为单例类是最简单的方式来创建线程安全单例模式的方式。

14、Java 中 sleep 方法和 wait 方法的区别?

虽然两者都是用来暂停当前运行的线程,但是 sleep() 实际上只是短暂停顿,因为它不会释放锁,而 wait() 意味着条件等待,这就是为什么该方法要释放锁,因为只有这样,其他等待的线程才能在满足条件时获取到该锁。

15、什么是不可变对象(immutable object)?Java 中怎么创建一个不可变对象?

  不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer 及其它包装类。详情参见答案,一步一步指导你在 Java中创建一个不可变的类。

16、我们能创建一个包含可变对象的不可变对象吗?

是的,我们是可以创建一个包含可变对象的不可变对象的,你只需要谨慎一点,不要共享可变对象的引用就可以了,如果需要变化时,就返回原对象的一个拷贝。最常见的例子就是对象中包含一个日期对象的引用。数据类型和 Java 基础面试问题

17、Java 中应该使用什么数据类型来代表价格?

  如果不是特别关心内存和性能的话,使用 BigDecimal,否则使用预定义精度的double 类型。

18、怎么将 byte 转换为 String?

  可以使用 String 接收 byte[] 参数的构造器来进行转换,需要注意的点是要使用的正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。

19、Java 中怎样将bytes[] 转换为 long 类型?

  bytes[] 到数字类型的转换是个经常用到的代码,解决方式也不止一种。

  java代码实现,如果不想借助任何已经有的类,完全可以自己实现这段代码,如下:

  1. /**
  2. * 将字节数组转为long<br>
  3. * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常
  4. * @param input
  5. * @param offset 起始偏移量
  6. * @param littleEndian 输入数组是否小端模式
  7. * @return
  8. */public static long longFrom8Bytes(byte[] input, int offset, Boolean littleEndian){
  9. long value=0;
  10. // 循环读取每个字节通过移位运算完成long的8个字节拼装
  11. for (int count=0;count<8;++count){
  12. int shift=(littleEndian?count:(7-count))<<3;
  13. value |=((long)0xff<< shift) & ((long)input[offset+count] << shift);
  14. }
  15. return value;}

借助java.nio.ByteBuffer实现

java.nio.ByteBuffer 本身就有getLong,getInt,getFloat….方法,只要将byte[]转换为ByteBuffer就可以实现所有primitive类型的数据读取,参见javadoc。

  1. /**
  2. * 利用 {@link java.nio.ByteBuffer}实现byte[]转long
  3. * @param input
  4. * @param offset
  5. * @param littleEndian 输入数组是否小端模式
  6. * @return
  7. */public static long bytesTolong(byte[] input, int offset, Boolean littleEndian) {
  8. // 将byte[] 封装为 ByteBuffer
  9. ByteBuffer buffer = ByteBuffer.wrap(input,offset,8);
  10. if(littleEndian){
  11. // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN)
  12. // ByteBuffer 默认为大端(BIG_ENDIAN)模式
  13. buffer.order(ByteOrder.LITTLE_ENDIAN);
  14. }
  15. 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 到 127。

2019年Java面试题基础系列228道(4)的更多相关文章

  1. 2019年Java面试题基础系列228道,题目汇总,可以先看会多少

    Java面试题(一) 1.面向对象的特征有哪些方面? 2.访问修饰符 public,private,protected,以及不写(默认)时的区别? 3.String 是最基本的数据类型吗? 4.flo ...

  2. 2019年Java面试题基础系列228道(1)

    1.面向对象的特征有哪些方面? 面向对象的特征主要有以下几个方面: 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注这些行为 ...

  3. 2019年Java面试题基础系列228道(3)

    51.类 ExampleA 继承 Exception,类 ExampleB 继承ExampleA. 有如下代码片断: try { throw new ExampleB("b")}c ...

  4. 2019年Java面试题基础系列228道(2)

    21.描述一下 JVM 加载 class 文件的原理机制? JVM 中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java 中的类加载器是一个重要的 Java 运行时系统组件,它 ...

  5. 2019年Java面试题基础系列228道(6)

    51.ArrayList 与 LinkedList 的不区别? 最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而LinkedList 的底层数据结构书链表,不支持随机访问. ...

  6. 2019年Java面试题基础系列228道(5)

    21.存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为C 么?如 C = (C) B: 这属于强制类型转换,如果被转换的B实例不是C类型,会有异常 比如你的ABC分别对应动物,猫,黑猫. ...

  7. 2019年 Java 面试题解析

    2019年 Java 面试题解析 转载地址:https://www.cnblogs.com/Zz-maker/p/11193930.html 作者: Zz_maker 包含的模块: 本文分为十九个模块 ...

  8. Java面试题-基础知识

    参考文章:Java面试题-基础知识 基础能力 什么是值传递和引用传递 线程状态有哪些,它们之间是如何转换的 进程与线程的区别,进程间如何通讯,线程间如何通讯? HashMap的数据结构是什么?如何实现 ...

  9. 18家大厂Java面试题整理了350道(分布式+微服务+高并发)

    一.性能调优系列 1.Tomcat性能调优 JVM参数调优: -Xms 表示JVM初始化堆的大小, -Xmx表示JVM堆的最大值.这两个值的大小一般根据需要进行设置. 当应用程序需要的内存超出堆的最大 ...

随机推荐

  1. python 之 列表常用 操作

  2. Day13:H5+JS+C3

    css布局中,什么是BFC BFC是Block formatting context的缩写,表示"块级格式化上下文". 设置BFC的元素,是一个独立的渲染区域,只有Block-le ...

  3. [昆仑会员卡系统]老会员数据导入 从临时表插入会员至member_info_svc表 SQL

    第一版无UUID版本 从临时表插入会员至member_info_svc表 insert into member_info_svc ( gh_no,chname,sex,birthday,tel,ema ...

  4. Picture Control 加载路径图片

    //CBitmap bitmap; //HBITMAP hBmp; //bitmap.LoadBitmap(strImgPath); //hBmp = (HBITMAP)bitmap.GetSafeH ...

  5. 关于Lombok的认识及其应用(一)

    目录 1.Lombok的介绍 2.Lombok的安装 3.Lombok实现原理分析 4.Lombok使用方法 4.1.@Data注解 4.2.@Getter/@Setter注解 1.Lombok的介绍 ...

  6. eclipse快捷键及设置【转】

    1.Eclipse设置新建菜单初始项 windows-->Perspective-->Customize Perspective--> 2.Eclipse快捷键 1. ctrl+sh ...

  7. 主要排序算法(Python实现)

    1. 冒泡排序 算法描述:1. 比较相邻的两个数,对升序(/降序)而言,若当前数小于(大于)后一个数则交换两者的位置. 2.那么循环长度为L的列表,从第一个元素到倒数第(L-1)元素进行第1步操作,其 ...

  8. python实用技巧之任务切分

    Python 大任务切分小任务 今天来说说,Python中的任务切分.以爬虫为例,从一个存 url 的 txt 文件中,读取其内容,我们会获取一个 url 列表.我们把这一个 url 列表称为大任务. ...

  9. Linux下java进程CPU占用率高分析方法(一)

    Linux下java进程CPU占用率高分析方法 在工作当中,肯定会遇到由代码所导致的高CPU耗用以及内存溢出的情况.这种情况发生时,我们怎么去找出原因并解决. 一般解决方法是通过top命令找出消耗资源 ...

  10. Tosca :配置环境参数

    # 跟Modules TestCases并列 ,右键创建 #再右键创建配置(结构自己安排) #再创建配置参数 #使用配置参数 #引用配置的环境参数