这里有新鲜出炉的 Java 并发编程示例, 程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
这篇文章主要为大家详细介绍了常见的 java 面试题, 具有一定的参考价值, 感兴趣的小伙伴们可以参考一下
1. Java 中 sleep 和 wait 的区别
这两个方法来自不同的类分别是, sleep 来自 Thread 类, 和 wait 来自 Object 类
sleep 是 Thread 的静态类方法, 谁调用的谁去睡觉, 即使在 a 线程里调用 b 的 sleep 方法, 实际上还是 a 去睡觉, 要让 b 线程睡觉要在 b 的代码中调用 sleep
锁: 最主要是 sleep 方法没有释放锁, 而 wait 方法释放了锁, 使得其他线程可以使用同步控制块或者方法
sleep 不出让系统资源; wait 是进入线程等待池等待, 出让系统资源, 其他线程可以占用 CPU 一般 wait 不会加时间限制, 因为如果 wait 线程的运行资源不够, 再出来也没用, 要等待其他线程调用 notify/notifyAll 唤醒等待池中的所有线程, 才会进入就绪队列等待 OS 分配系统资源 sleep(milliseconds)可以用时间指定使它自动唤醒过来, 如果时间不到只能调用 interrupt()强行打断
Thread.sleep(0)的作用是触发操作系统立刻重新进行一次 CPU 竞争
使用范围: wait,notify 和 notifyAll 只能在同步控制方法或者同步控制块里面使用, 而 sleep 可以在任何地方使用
- synchronized(x) {
- x.notify()
- // 或者 wait()
- }
2. Java 中 HashMap 和 HashTable 的区别
历史原因: Hashtable 是给予陈旧的 Dictonary 类的, HashMap 是 Java1.2 引进的 Map 接口的一个实现
HashMap 允许空的键值对, 而 HashTable 不允许
HashTable 同步, 而 HashMap 非同步, 效率上比 HashTable 要高
3. 请简述在异常当中, throw 和 throws 有什么区别
throw 代表动作, 表示抛出一个异常的动作; throws 代表一种状态, 代表方法可能有异常抛出
throw 用在方法实现中, 而 throws 用在方法声明中
throw 只能用于抛出一种异常, 而 throws 可以抛出多个异常
4. 内存溢出和内存泄露的区别
内存溢出 out of memory, 是指程序在申请内存时, 没有足够的内存空间供其使用, 出现 out of memory; 比如申请了一个 integer, 但给它存了 long 才能存下的数, 那就是内存溢出
内存泄露 memory leak, 是指程序在申请内存后, 无法释放已申请的内存空间, 一次内存泄露危害可以忽略, 但内存泄露堆积后果很严重, 无论多少内存, 迟早会被占光
memory leak 会最终会导致 out of memory!
内存溢出就是你要求分配的内存超出了系统能给你的, 系统不能满足需求, 于是产生溢出
内存泄漏是指你向系统申请分配内存进行使用(new), 可是使用完了以后却不归还(delete), 结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了), 而系统也不能再次将它分配给需要的程序一个盘子用尽各种方法只能装 4 个果子, 你装了 5 个, 结果掉倒地上不能吃了这就是溢出! 比方说栈, 栈满时再做进栈必定产生空间溢出, 叫上溢, 栈空时再做退栈也产生空间溢出, 称为下溢就是分配的内存不足以放下数据项序列, 称为内存溢出
以发生的方式来分类, 内存泄漏可以分为 4 类:
常发性内存泄漏发生内存泄漏的代码会被多次执行到, 每次被执行的时候都会导致一块内存泄漏
偶发性内存泄漏发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生常发性和偶发性是相对的对于特定的环境, 偶发性的也许就变成了常发性的所以测试环境和测试方法对检测内存泄漏至关重要
一次性内存泄漏发生内存泄漏的代码只会被执行一次, 或者由于算法上的缺陷, 导致总会有一块仅且一块内存发生泄漏比如, 在类的构造函数中分配内存, 在析构函数中却没有释放该内存, 所以内存泄漏只会发生一次
隐式内存泄漏程序在运行过程中不停的分配内存, 但是直到结束的时候才释放内存严格的说这里并没有发生内存泄漏, 因为最终程序释放了所有申请的内存但是对于一个服务器程序, 需要运行几天, 几周甚至几个月, 不及时释放内存也可能导致最终耗尽系统的所有内存所以, 我们称这类内存泄漏为隐式内存泄漏
从用户使用程序的角度来看, 内存泄漏本身不会产生什么危害, 作为一般的用户, 根本感觉不到内存泄漏的存在真正有危害的是内存泄漏的堆积, 这会最终消耗尽系统所有的内存从这个角度来说, 一次性内存泄漏并没有什么危害, 因为它不会堆积, 而隐式内存泄漏危害性则非常大, 因为较之于常发性和偶发性内存泄漏它更难被检测到
5. String,StringBuffer 和 StringBuilder 的区别
可变与不可变
String 类中使用字符数组保存字符串, 如下就是, 因为有 final 修饰符, 所以可以知道 string 对象是不可变的
private final char value[];
StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类, 在 AbstractStringBuilder 中也是使用字符数组保存字符串, 如下就是, 可知这两种对象都是可变的
char[] value;
是否多线程安全
String 中的对象是不可变的, 也就可以理解为常量, 显然线程安全
AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类, 定义了一些字符串的基本操作, 如 expandCapacityappendinsertindexOf 等公共方法
StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁, 所以是线程安全的看如下源码:
- public synchronized StringBuffer reverse() {
- super.reverse();
- return this;
- }
- public int indexOf(String str) {
- return indexOf(str, 0); // 存在 public synchronized int indexOf(String str, int fromIndex) 方法
- }
StringBuilder 并没有对方法进行加同步锁, 所以是非线程安全的
StringBuilder 与 StringBuffer 共同点
StringBuilder 与 StringBuffer 有公共父类 AbstractStringBuilder(抽象类)
抽象类与接口的其中一个区别是: 抽象类中可以定义一些子类的公共方法, 子类只需要增加新的功能, 不需要重复写已经存在的方法; 而接口中只是对方法的申明和常量的定义
StringBuilderStringBuffer 的方法都会调用 AbstractStringBuilder 中的公共方法, 如 super.append(...)只是 StringBuffer 会在方法上加 synchronized 关键字, 进行同步
最后, 如果程序不是多线程的, 那么使用 StringBuilder 效率高于 StringBuffer
6. 数组和链表的区别
二者都属于一种数据结构
从逻辑结构来看:
数组必须事先定义固定的长度(元素个数), 不能适应数据动态地增减的情况当数据增加时, 可能超出原先定义的元素个数; 当数据减少时, 造成内存浪费; 数组可以根据下标直接存取
链表动态地进行存储分配, 可以适应数据动态地增减的情况, 且可以方便地插入删除数据项 (数组中插入删除数据项时, 需要移动其它数据项, 非常繁琐) 链表必须根据 next 指针找到下一个元素
从内存存储来看:
(静态)数组从栈中分配空间, 对于程序员方便快速, 但是自由度小
链表从堆中分配空间, 自由度大但是申请管理比较麻烦
从上面的比较可以看出, 如果需要快速访问数据, 很少或不插入和删除元素, 就应该用数组; 相反, 如果需要经常插入和删除元素就需要用链表数据结构了
7. ArrayList 和 LinkedList 的区别
ArrayList 是实现了基于动态数组的数据结构, LinkedList 基于链表的数据结构
对于随机访问 get 和 set,ArrayList 觉得优于 LinkedList, 因为 LinkedList 要移动指针
对于新增和删除操作 add 和 remove,LinedList 比较占优势, 因为 ArrayList 要移动数据
来源: http://www.phperz.com/article/18/0212/359401.html