【Java基础】常用知识积累(一)

1、==和equals的区别 null和""的区别

2、15个顶级Java多线程面试题及回答

        (1)、线程中join的使用

       在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

     (2)、线程中synchronized 与 Lock 的那点事

     (3)、线程中死锁问题

        (4)、在java中wait和sleep方法的不同?
      通常会在电话面试中经常被问到的Java线程面试问题。最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

      (5)、Java多线程原子操作

        SerialNumberGenerator大概是你能想到的最简单的例子了。如果你是从C++转过来的,或者有其它低级语言的经验,你会认为递增肯定是一个原子操作,因为它通常都是用CPU的指令来实现的。但是在JVM里,递增不是原子操作,它涉及到了读和写。所以即便是这么简单的一个操作,多线程也有机可乘。

         

public class SerialNumberGenerator {
private static volatile int serialNumber = 0;
public static int nextSerialNumber() {
return serialNumber++;
}
}

        serialNumber字段是volatile的,这样所有线程的serialNumber字段值保持一致。
        多线程工作中有主内存和工作内存之分,在JVM中有一个主内存,专门负责所有线程共享数据;而每个线程都有它自己私有的工作内存,volatile变量表示保证它必须是与主内存保持一致,它实际是变量的同步

3、为什么说Java的String对象是不可变的

     根据JDK中java.lang.String的源码进行分析,从中可以得出String类型的对象不可变的原因,大致上有如下两个:
     (1)、java.lang.String类型在实现时,其内部成员变量全部使用final来修饰,保证成员变量的引用值只能通过构造函数来修改;
     (2)、java.lang.String类型在实现时,在外部可能修改其内部存储值的函数实现中,返回时一律构造新的String对象或者新的byte数组或者char数组;
        第2的重要性在于,假如通过String类型的toCharArray方法可以直接访问String类型内部定义的char数组,那么即便String类型内部的char数组使用了final来修饰,也仅仅保证这个成员变量的引用不可变,而无法保证引用指向的内存区域不可变。由上述两点,保证外部不可能修改java.lang.String类型对象的内部属性,从而保证String对象是不可变的。

4、StringBuffer和StringBuilder

       提到String,就不得不提一下JDK中存在另外两个常用来表示字符串的类,StringBuffer和StringBuilder。根据注释,StringBuffer可谓老资格了,从JDK1.0时即伴随Java征战世界,而StringBuilder直到JDK1.5时才出现。

StringBuffer和StringBuilder的共同点:
 (1)、都是可变对象,对象内的字符缓存会随着拼接操作而动态扩展;
 (2)、用来完成字符串拼接操作;
 (3)、构造时传入内部缓存大小时,可以降低缓存扩展的次数,明显提升字符串拼接操作的效率;
StringBuffer和StringBuilder的区别:
 (1)、StringBuilder的方法都是线程不安全的,从另外一个角度讲,StringBuilder类型的对象在做字符串拼接操作时,由于少了线程同步的操作,执行效率上有很大提升;
 (2)、StringBuffer的方法都加上了synchronized关键字,因而在一定的场景下,StringBuffer类型的对象都是线程安全的,但在执行效率上,由于多了线程同步的操作,因而会有少许的损失;
   在大多数场景下,字符串拼接操作都是不需要考虑多线程环境下对结果的影响的,因而使用StringBuilder类型可以提升代码的执行效率。
   在多个线程的代码中共享同一个StringBuffer类型的对象时,需要关注synchronized关键字对最终结果的影响。由于StringBuffer类的实现中,仅仅对每个方法使用了synchronized修饰,这只能保证在多线程场景下,访问StringBuffer对象的同一个方法时可以保证最终结果的一致性,假如一个线程访问A方法,另外一个线程方法B方法,则由于加锁对象的不同,可能会出现不一致的现象,这是需要程序员特别要注意的地方。类似的,可以参考Vector的实现和应用场景。


你可能感兴趣的:(java,多线程,线程,面试,面试题)