一、什么是线程同步、异步?
(更多面试题推荐:java面试题)
同步(synchronous)就是协同步调,按预定的先后次序进行运行。
异步就是和同步相对,不阻塞,同时运行。
二、什么是线程不安全?如何解决?(重点)
什么叫线程安全?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
(相关教程推荐:java入门程序)
为什么ArrayList线程不安全?不安全为什么要使用?如何解决线程不安全?
一个 ArrayList ,在添加一个元素的时候,它可能会有两步来完成:
1、在 Items[Size] 的位置存放此元素;
2、增大 Size 的值。
在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。
但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。
那好,现在我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。
如何解决?
加锁(对象锁、锁代码块)、自旋+CAS方式(乐观锁)、使用java提供的线程安全的数据类
三、如何创建一个线程?有几种方法?
1、继承Thread类
2、实现Runnable接口
3、实现Callable接口
四、是使用Runnalbe接口好?还是继承Thread类好?
实现Runnable接口更好一些。
1、因为实现Runnable接口可以避免Java单继承的局限性。
当一个类继承了Thread,就不可以在继承其他类了。而当一个类实现了Runnable,它一样可以继承其他类。
2、更符合面向对象的设计
run()方法的作用是用来封装线程要运行的代码。那么run()方法所属的对象,就是线程任务对象。Thread类的子类对象即使线程对象,又是线程任务对象。耦合性很强。
有了Runnable接口,可以将线程任务和线程进行解耦,提高了程序的扩展性。
(相关视频教程推荐:java视频教程)
五、sleep()和 wait()有什么区别?
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
如果变量被声明为volatile,在每次访问时都会和主存一致;如果变量在同步方法或者同步块中 被访问,当在方法或者块的入口处获得锁以及方法或者块退出时释放锁时变量被同步。