Java 面试知识点解析(二)——高并发编程篇 (6)

答:可以使基本数据类型以原子的方式实现自增自减等操作。参考博客:concurrent.atomic包下的类AtomicInteger的使用

8)创建线程有哪几种方式?

答:有两种创建线程的方法:一是实现Runnable接口,然后将它传递给Thread的构造函数,创建一个Thread对象;二是直接继承Thread类。

面试官:两种方式有什么区别呢?

继承方式:

(1)Java中类是单继承的,如果继承了Thread了,该类就不能再有其他的直接父类了.

(2)从操作上分析,继承方式更简单,获取线程名字也简单.(操作上,更简单)

(3)从多线程共享同一个资源上分析,继承方式不能做到.

实现方式:

(1)Java中类可以多实现接口,此时该类还可以继承其他类,并且还可以实现其他接口(设计上,更优雅).

(2)从操作上分析,实现方式稍微复杂点,获取线程名字也比较复杂,得使用Thread.currentThread()来获取当前线程的引用.

(3)从多线程共享同一个资源上分析,实现方式可以做到(是否共享同一个资源).

9)run() 方法和 start() 方法有什么区别?

答:start() 方法会新建一个线程并让这个线程执行 run() 方法;而直接调用 run() 方法知识作为一个普通的方法调用而已,它只会在当前线程中,串行执行 run() 中的代码。

10)你怎么理解线程优先级?

答:Java 中的线程可以有自己的优先级。优先极高的线程在竞争资源时会更有优势,更可能抢占资源,当然,这只是一个概率问题。如果运行不好,高优先级线程可能也会抢占失败。

由于线程的优先级调度和底层操作系统有密切的关系,在各个平台上表现不一,并且这种优先级产生的后果也可能不容易预测,无法精准控制,比如一个低优先级的线程可能一直抢占不到资源,从而始终无法运行,而产生饥饿(虽然优先级低,但是也不能饿死它啊)。因此,在要求严格的场合,还是需要自己在应用层解决线程调度的问题。

在 Java 中,使用 1 到 10 表示线程优先级,一般可以使用内置的三个静态标量表示:

public final static int MIN_PRIORITY = 1; public final static int NORM_PRIORITY = 5; public final static int MAX_PRIORITY = 10;

数字越大则优先级越高,但有效范围在 1 到 10 之间,默认的优先级为 5 。

11)在 Java 中如何停止一个线程?

答:Java 提供了很丰富的 API 但没有为停止线程提供 API 。

JDK 1.0 本来有一些像 stop(),suspend() 和 resume() 的控制方法但是由于潜在的死锁威胁因此在后续的 JDK 版本中他们被弃用了,之后 Java API 的设计者就没有提供一个兼容且线程安全的方法来停止任何一个线程。

当 run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用 volatile 布尔变量来退出 run() 方法的循环或者是取消任务来中断线程。

12)多线程中的忙循环是什么?

答:忙循环就是程序员用循环让一个线程等待,不像传统方法 wait(),sleep() 或yield() 它们都放弃了 CPU 控制权,而忙循环不会放弃 CPU,它就是在运行一个空循环。这么做的目的是为了保留 CPU 缓存。

在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存,为了避免重建缓存和减少等待重建的时间就可以使用它了。

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

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

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

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

// The standard idiom for using the wait method synchronized (obj) { while (condition does not hold) obj.wait(); // (Releases lock, and reacquires on wakeup) ... // Perform action appropriate to condition }

参见 Effective Java 第 69 条,获取更多关于为什么应该在循环中来调用 wait 方法的内容。

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

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

Java 面试知识点解析(二)——高并发编程篇

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdwjz.html