Java基础知识面试参考指南

本文为即将参加面试的Java程序员准备了一些面试常见的Java的基础知识,帮你准备好面试的硬实力。

同步

在多线程程序中,同步修饰符用来控制对临界区代码的访问。其中一种方式是用synchronized关键字来保证代码的线程安全性。在Java中,synchronized修饰的代码块或方法不会被多个线程并发访问。它强制要求线程在进入一个方法之前获得一个锁,在离开方法时释放该锁。它保证了在同一时刻只有一个线程能执行被其修饰的方法。

如果我们把一个方法或代码块定义为同步的,就意味着在同一个对象中,只会有一个对同步方法的调用。如果在一个线程内部调用了一个同步方法,则其他线程会一直阻塞,直到第一个线程完成方法调用。

在进入一个对象的同步方法之前,需要申请对该对象上锁,完成方法调用后释放锁供其他线程申请。同步方法遵循happens-before机制,它保证了对象状态的改变在其他线程中都是可见的。

当标记一个代码块为同步时,需要用一个对象作为参数。当一个运行线程执行到该代码块时,要等到其他运行线程退出这个对象的同步代码区。然而,一个线程可以进入另一个对象的同步代码区。但是同一个对象的非同步方法可以不用申请锁。

如果定义一个静态方法为同步,则是在类上同步,而不是在对象上同步。也即如果一个静态同步方法在执行时,整个类被锁住,对该类中的其他静态方法调用会阻塞。

1)当一个线程进入了一个实例的同步方法,则其他任何线程都不能进入该实例的任何一个同步方法。

2)当一个线程进入了一个类的静态同步方法,则其他任何线程都不能进入该类的任何一个静态同步方法。

注意:

同步的静态方法和非静态方法之间没有关系。也即静态同步方法和非静态同步方法可以同时执行,除非非静态同步方法显式在该类上同步(例如,synchronized(MyClass.class){…})

类的构造函数不能定义成同步的。

监视器或内部锁

锁限制了对某个对象状态的访问,同时保证了happens-before关系。

每个对象都有一个锁对象,一个线程在访问对象之前必须申请锁,完成以后释放锁。其他线程不能访问对象,知道获得该对象的锁。这保证了一个线程改变了对象的状态后,新的状态对其他在同一个监视器上线程可见。

当线程释放锁时,会将cache中的内容更新到主内存,这也就使得该对象的状态变化对其他线程是可见的——这就是happens-before关系。

synchronized和volatile,包括Thread.start()和Thread.join()方法,都能保证happens-before关系。

同步语句和同步方法获取的锁相同,某个线程可以请求同一个锁多次。

一个线程获得了对象锁后,不会影响其他线程访问对象的字段或调用对象的非同步方法。

同步语句首先尝试获取对象的锁,获取成功后立即开始执行同步代码块,执行完后释放锁。

如果方法是对象成员或对象实例,线程将锁住该实例。如果方法是静态的,线程锁住的是该类对应的Class对象。同步方法用SYNCHRONIZED标记,该标记被方法调用指令识别。

原子变量

来看语句intc++,它包含多个操作,e.g.从内存读取c的值,将c的值加1,然后写回内存。这个操作对单线程来说是正确的,但是在多线程环境却可能出错。它存在竞态条件,在多线程环境中可能多个线程同时读取c的值

原子访问保证所有操作作为一个整体一次完成。一个原子操作要么完全执行要么完全不执行。

以下这些操作能认为是原子操作:

对引用类型和大部分基本数据类型(long和double类型除外)的读和写操作。

声明为volatile类型变量的读和写操作(包括long和double变量)。

Java并发包java.util.concurrent.atomic定义了对单个变量进行原子操作的类。所有类都有get和set方法,就像对volatile变量的读写一样。这就意味着,一个写操作happens-before其他任何对该变量的读操作。原子方法







































北京一次治疗白癜风花多少钱
白癜风是什么



转载请注明:http://www.guyukameng.com/cssdiv/cssdiv/10132.html