经过自己这段时间的面试整理的一些常见的面试题(会不断补充),希望自己早日面试成功!

1、Java怎么实现多线程同步?

为何要使用同步:

  Java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前被其他线程调用,从而保证了该变量的唯一性和准确性。

(1)同步方法

  即有synchronized关键字修饰的方法。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

  由于Java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

  代码如:

  public synchronize void save(){}

  注:synchronize关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。

(2)同步代码块

  即有synchronize关键字修饰的语句块。

  被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。

  代码如:

  public void save(int money){

    synchronize(this){

      需要修饰的具体代码块...

    }

  }

(3)使用特殊变量(volatile)实现线程同步

(4)使用重入锁实现线程同步

(5)使用局部变量实现线程同步

(6)使用阻塞队列实现线程同步

(7)使用原子变量实现线程同步

这里只针对具体有哪些方法做个总结,每种方法的具体实现请移步此博客:(https://www.cnblogs.com/XHJT/p/3897440.html)。

2、字节流和字符流转换的桥梁是什么?

InputStreamReader(把字节流转向字符流)

OutputStreamWriter(把字符流转换为字符流)

具体详见:(https://blog.csdn.net/baidu_41924510/article/details/80146168)。

3、Java中线程安全是什么意思,HashMap是线程安全的吗?

我对Java多线程的了解不多,只简单地用过两次,我有次实现的一个缓存的功能,用一个HashMap做个缓存的容器,这个在单线程的条件下使用没有问题,如果需要支持多线程就要使用支持并发的集合容器。我知道有个ConcurentHashMap可以做到线程安全,但是我自己做测试没发现ConcurentHashMap和HashMap有什么具体的差别,我就去看文档,了解了一些东西,现在对并发使用懂的不太多。

这个是在百度贴吧看到的一个小伙伴分享的回答技巧,感觉这样回答确实挺有逼格的所以就摘抄了下来,附上链接(http://tieba.baidu.com/f?kz=5563378214&mo_device=1&ssid=0&from=1086k&uid=0&pu=usm@1,sz@1320_2002,ta@iphone_1_12.2_2_9.1&bd_page_type=1&baiduid=261BF40508439E890450C10A775CADDC&tj=www_normal_10_20_10_title&referer=m.baidu.com?pn=0&&red_tag=t0102336054)。

下面是准确答案:

就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的就不能再对它进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问。

什么叫线程安全:

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果都和单线程运行结果是一样的,而且其他变量的值也和预期的是一样的,就是线程安全的。

或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致改接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。

线程安全问题都是由全局变量及静态变量引起的。

若每个线程中对全局变量、只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般就需要考虑线程同步,否则就可能影响线程安全。

存在竞争的线程不安全,不存在竞争的线程就是安全的。

HashMap是非线程安全的。

4、Java中的ArrayList是如何实现动态扩容的?

这个问题你可以简单的回答,将原有数组拷贝到一个新的更大的数组中,然后抛弃原来的数组。不过你还可以加上这样一句话,我自己对这个问题也很好奇,我就看了下源代码,然后自己实现了这个动态扩容的功能,就是如果需要收缩的时候需要手动释放内存。这个问题的回答让面试官对你的学习能力有了认可。当然如果他还要继续顺着这个问题问你,Java中有垃圾收集器可以自动释放内存,你为什么要自己手动释放呢,你就可以回答,因为这个数组的内存现在不归垃圾收集器管理了,需要自己管理。这就是实现这类功能需要注意的问题。

(来自上面贴吧那个小伙伴)

5、Java的switch语句是否支持String类型的?

对Java有了解的都知道Java从JDK7开始支持,如果你只简单的回答这个问题,并不能吸引面试官。这个时候要展示你的思考能力和独特的见解。你可以这样回答,Java在JDK6之前是不支持的,从JDK7开始支持,主要是因为使用switch(String)的时候太多了,Oracle为了提高开发效率引入了这个新的语言特性,这是需求驱动的结果。这也说明昨天不支持的东西可能下个版本就支持了,这正是软件开发行业日新月异的特色。如果你这样回答逼格就提升了不少,你从面试中胜出的可能性就增加了。

(来自上面贴吧那个小伙伴)

6、什么是线程池?为什么要使用它?

创建线程需要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫做工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。

引用自(http://f.dataguru.cn/java-913890-1-1.html)。

7、Java实现几种常见的排序方法。

冒泡排序:

 1 public static void bubbleSort(int[] a) {
 2     int temp;
 3     int size = a.length;
 4     for(int i=1; i<size; i++) {
 5         for(int j=0; j<size-i; j++) {
 6             if(a[j] < a[j+1]) {
 7                 temp = a[j];
 8                 a[j]=a[j+1];
 9                 a[j+1]=temp;
10             }
11         }
12         for(int aa : a)
13             System.out.print(aa+",");
14         System.out.println();
15     }
16 }

 

详见(https://www.cnblogs.com/wangmingshun/p/5635292.html)。

8、HashMap的工作原理?

HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用建对象的hashCode()方法来计算hashcode,然后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。HashMap在每个链表节点中储存键值对对象。

9、当两个不同的键对象的hashcode相同时会发生什么?

它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。

10、HashMap和HashTable的区别?

HashMap和HashTable都实现了Map接口,主要的区别有:线程安全性,同步(synchronization),以及速度。

(1)HashMap几乎可以等价于HashTable。除了HashMap是非synchronize(同步)的,并可以接受为null(空)的键(key)和值(value),而HashTable则不行

(2)HashMap是非同步的,而HashTable是同步的,意味着HashMap是线程不安全的,而HashTable是线程安全的,多个线程可以共享一个HashTable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java5提供了ConcurentHashMap,他是HashTable的替代,比HashTable的扩展性更好。

(3)由于HashTable是线程安全的也是同步(synchronized)的,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过HashTable

(4)HashMap不能保证随着时间的推移Map中的元素次序是不变的。

11、我们能否让HashMap同步?

HashMap可以通过下面的语句进行同步:

map m = Collections.synchronizeMap(hashMap);

12、HashMap和HashSet的区别?

(1)HashMap实现了Map接口,HashSet实现了Set接口

(2)HashMap储存键值对,HashSet仅仅储存对象

(3)HashMap使用put()方法将元素放入map中,HashSet使用add()方法将元素放入set中

(4)HashMap中使用键对象来计算hashcode值,HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false

(5)HashMap比较快,因为是使用唯一的键来获取对象,HashSet较HashMap来说比较慢

关于HashMap的更多知识详见博客(https://blog.csdn.net/suifeng629/article/details/82179996)。

13、HashMap和TreeMap的区别?

HashMap和TreeMap都是线程不安全的,都是key不允许重复,value允许重复。

HashMap中元素的排列顺序是不固定的,而 TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap。

HashMap适用于在Map中插入、删除和定位元素。
Treemap适用于按自然顺序或自定义顺序遍历键(key)。

HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap。

Java中HashMap和TreeMap的区别深入理解:(https://www.cnblogs.com/williamjie/p/9099130.html)。

 

HashMap:基于哈希表实现,数组方式存储key/value,允许null作为key和value,不保证元素迭代顺序是按照插入时的顺序,key的hash值是先计算key的hashcode值,然后再进行计算,每次容量扩容会重新计算所以key的hash值,会消耗资源,要求key必须重写equals和hashcode方法

默认初始容量16,加载因子0.75,扩容为旧容量乘2,查找元素快,如果key一样则比较value,如果value不一样,则按照链表结构存储value,就是一个key后面有多个value;

TreeMap:基于红黑二叉树的NavigableMap的实现,不允许null,存入TreeMap的元素应当实现Comparable接口或者实现Comparator接口,会按照排序后的顺序迭代元素,两个相比较的key不得抛出classCastException。主要用于存入元素的时候对元素进行自动排序,迭代输出的时候就按排序顺序输出

14、Java中堆内存和栈内存中分别存放什么?

堆内存:存放所有new出来的对象

栈内存:存放基本类型的变量,对象的引用和方法的调用,遵循先入后出的规则

浅析Java中堆内存和栈内存的区别:(https://blog.csdn.net/jxq0816/article/details/78757952)。

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄