多线程、并发及线程的基础问题

目录

1)Java 中能创建 Volatile数组吗?

2)volatile 能使得⼀个⾮原⼦操作变成原⼦操作吗?

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

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

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

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

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

8)什么是 Busy spin?我们为什么要使⽤它?

9)Java 中怎么获取⼀份线程dump ⽂件?

10)Swing 是线程安全的?

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

12)Java 中 sleep ⽅法和 wait ⽅法的区别?

13)什么是不可变对象(immutableobject)?

14)我们能创建⼀个包含可变对象的不可变对象吗?


1)Java 中能创建 Volatile数组吗?

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

2)volatile 能使得⼀个⾮原⼦操作变成原⼦操作吗?

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

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

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

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

volatile类型变量提供顺序可见性保证,例如jvm或者jit为了获得更好的性能会对语句重排序,但是volatile类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。volatile提供happens-before的保证

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

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

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

wait()方法应该在循环调用,因为当线程获取到cpu开始执行的时候,其他条件可能还没满足,所以在处理前,循环检测条件是否满足会更好

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

伪共享是多线程系统(每个处理器有自己的局部缓存)中一个众所周知的性能问题。伪共享发生在不同处理器上的线程对变量的修改依赖于相同的缓存行。伪共享问题很难被发现,因为线程可能访问完全不同的局部变量,内存中却碰巧在很相近的位置上。如其他诸多的并发问题,避免伪共享的最基本方式是仔细审查代码,根据缓存行来调整你的数据结构。

8)什么是 Busy spin?我们为什么要使⽤它?

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

9)Java 中怎么获取⼀份线程dump ⽂件?

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

10)Swing 是线程安全的?

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

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

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

12)Java 中 sleep ⽅法和 wait ⽅法的区别?

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

13)什么是不可变对象(immutableobject)?

不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如String、Integer及其它包装类

14)我们能创建⼀个包含可变对象的不可变对象吗?

是的,我们是可以创建一个包含可变对象的不可变对象的,你只要谨慎一点,不要共享可变对象的引用就可以了,如果需要变化时,就返回原对象的一个拷贝。最常见的例子就是对象中包含一个日期对象的引用。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xinyi_java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值