一、String和Stringbuffer和StringBuilder的区别?
String:字符串常量
StringBuffer:字符串变量;线程安全的
StringBuilder:字符串变量;线程非安全的
三者执行速度比较:StringBuilder > StringBuffer > String
1.String类的内容一旦声明后是不可改变的,改变的只是其内存的指向,而StringBuffer类的对象内容是可以改变的。
2.对于StringBuffer,不能像String那样直接通过赋值的方式完成对象实例化,必须通过构造方法的方式完成。
3.StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于字符串类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入,删除等操作,使用StringBuffer要更加适合一些。
4.StringBuilder,StringBuffer 之间的最大不同在于 StringBuilder 的方法是线程非安全的(不能同步访问)。
5.StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类,然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
StringBuilder与StringBuffer二者的区别主要是在运行速度和线程安全这两方面。
1、StringBuffer 与 StringBuilder 中的方法和功能完全是等价的
2、只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
3、在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低。
三者使用的总结:1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
二、ArrayList,Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized思路方法(线程安全) ,通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项前后项即可,所以插入速度较快
三、HashMap和Hashtable的区别
HashMap:①线程非安全的
②性能方面:由于线程是非安全的,所以每个方法不需要阻塞其他线程,所以性能要优于HashTable
③空值问题:允许键值为Null
④实现方式:继承AbstractMap类
⑤扩容:源码中初始值 1 << 4 ,初始值为16,负载因子默认为0.75(详细请看该链接下《说说hashMap 使用的是哪种数据结构》链接内容)
⑥迭代器:HashMap 中的 Iterator 迭代器是 fail-fast 的,当其他线程改变了HashMap 的结构,如:增加、删除元素,将会抛出 ConcurrentModificationException 异常,而 Hashtable 则不会。
HashTable:①线程安全的,线程安全的原因是所有的元素操作都是用synchronized修饰的,而HashMap没有
②性能方面:由于是线程安全的,所以每个方法需要阻塞其他线程,所以性能要弱于HashMap
③空值问题:不允许键值为null
④实现方式:继承Dictionary类
⑤扩容:源码中初始值为11,负载因子默认为0.75
⑥迭代器: Hashtable 的 Enumerator 不是 fail-fast 的,Enumeration是个接口,不是类,再次,这个东西就是为了实现遍历的,现在已经被迭代器Iterator取代了,Enumeration和iterator最主要区别,其实就是Iterator可以删除元素,但是Enumration却不能。
最大的区别是,Hashtable的思路方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的思路方法实现同步,而HashMap 就必须为的提供外同步。
四、 final, finally, finalize的区别
final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
finally:是异常处理语句结构的一部分,表示总是执行。
finalize:是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。
五、swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
swtich中只能用byte short int char
六、线程的几种状态
创建:当new了一个线程,并没有调用start之前,线程处于创建状态;
就绪:当调用了start之后,线程处于就绪状态,这是,线程调度程序还没有设置执行当前线程;
运行:线程调度程序执行到线程时,当前线程从就绪状态转成运行状态,开始执行run方法里边的代码;
阻塞:线程在运行的时候,被暂停执行(通常等待某项资源就绪后在执行,sleep、wait可以导致线程阻塞),这是该线程处于阻塞状态;
死亡:当一个线程执行完run方法里边的代码或调用了stop方法后,该线程结束运行
生命周期如下图:
七、多线程有几种实现方式?
多线程的几种实现方式:①继承Thread类,重写Run()
②实现Runnable接口,创建步骤如下:
定义一个类实现Runnable接口,作为线程任务类
重写run方法,并实现方法体,方法体的代码就是线程所执行的代码
定义一个可以运行的类,并在main方法中创建线程任务类
创建Thread类,并将线程任务类做为Thread类的构造方法传入
启动线程
③使用内部类的方式:将Thread和Runnable作为内部子类实现
④定时器:定时器Timer(JDK提供API)是一个基于线程的工具类,可以定时的来执行某个任务。 提供定时任务的三方框架:Spring的Schedule和Quartz框架
⑤带返回值的线程实现方式:
1)实现Callable接口,实现call(),这个接口类似于Runnable接口,但比Runnable接口更加强大, 增加了异常和返回值。
2)创建一个FutureTask,指定Callable对象,做为线程任务。
3)创建线程,指定线程任务。
4)启动线程
⑥基于线程池的方式:
概念:一些线程的集合称为线程池,线程池可以很好的提高性能,线程池在系统启动时创建大量的空闲线程,程序将任务提交以后,线程就会启动一个线程执行该任务,任务结束以后,线程并不会死亡,而是返回线程池,成为空闲状态,当代执行下一个任务。
工作机制:①在线程池的编程模式下,任务是提交给整个线程池的,而不是直接提交给某一个线程,线程池在获取到任务后,会寻找是否有空闲的线程,如果有则将任务提交给这个线程
②一个线程只能执行一个任务,但可以同时向一个线程池提交多个任务
使用线程池的原因:多线程运行时,系统会不断的启动和关闭新线程,成本高,会过度消耗资源,以及过度的切换线程,会造成系统资源的崩溃,所以,线程池是最优选择
四种常见的线程池:
①线程池的返回值都是ExecutorService,ExecutorService是Java提供的用于管理线程池的类。该类作用是:控制线程数量和重用线程
②四种线程池介绍:
1)Executors.newCacheThreadPool():可缓存线程池,先查看池中有没有以前建立的线程,如果有,就直接使用。如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务
2)Executors.newFixedThreadPool(int n):创建一个可重用固定个数的线程池,以共享的无界队列方式来运行这些线程。
3)Executors.newScheduledThreadPool(int n):创建一个定长线程池,支持定时及周期性任务执行
4)Executors.newSingleThreadExecutor():创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
八、线程池的参数总结:
①corePoolSize:核心线程数
* 核心线程会一直存活,及时没有任务需要执行
* 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
* 设置 allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
②queueCapacity:任务队列容量(阻塞队列)
* 当核心线程数达到最大时,新任务会放在队列中排队等待执行
③maxPoolSize:最大线程数
* 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
* 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
④keepAliveTime:线程空闲时间
* 当线程空闲时间达到 keepAliveTime时,线程会退出,直到线程数量=corePoolSize
* 如果 allowCoreThreadTimeout=true,则会直到线程数量=0
⑤allowCoreThreadTimeout:允许核心线程超时
⑥rejectedExecutionHandler:任务拒绝处理器
* 两种情况会拒绝处理任务:
- 当线程数已经达到 maxPoolSize ,切队列已满,会拒绝新任务
- 当线程池被调用 shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用 shutdown()和线程池真正 shutdown之间提交任务,会拒绝新任务
* 线程池会调用 rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常
* ThreadPoolExecutor类有几个内部实现类来处理这类情况:
- AbortPolicy 丢弃任务,抛运行时异常
- CallerRunsPolicy 执行任务
- DiscardPolicy 忽视,什么都不会发生
- DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
* 实现 RejectedExecutionHandler 接口,可自定义处理器
基于JDK1.8的ConcurrentHashMap的源码分析:
ConcurrentHashMap是线程安全的,利用的是 CAS算法和Synchronized 来保证并发更新的安全
数据机构是:数组+链表+红黑树
重要的成员变量:
table:默认为null,初始化发生在第一次插入操作,默认大小为16的数组,用来存储Node节点数据,扩容时大小总是2的幂次方。
nextTable:默认为null,扩容时新生成的数组,其大小为原数组的两倍。
sizeCtl :默认为0,用来控制table的初始化和扩容操作,具体应用在后续会体现出来。
① -1 代表table正在初始化
②-N 表示有N-1个线程正在进行扩容操作
③其余情况:
1、如果table未初始化,表示table需要初始化的大小。
2、如果table初始化完成,表示table的容量,默认是table大小的0.75倍,居然用这个公式算0.75(n - (n >>> 2))。
```
public classConcurrentHashMapextendsAbstractMapimplementsConcurrentMap, Serializable {private static final longserialVersionUID = 7249069246763182397L;// 表的最大容量private static final intMAXIMUM_CAPACITY = 1 << 30;// 默认表的大小private static final intDEFAULT_CAPACITY = 16;// 最大数组大小static final intMAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 默认并发数private static final intDEFAULT_CONCURRENCY_LEVEL = 16;// 装载因子private static final floatLOAD_FACTOR = 0.75f;// 转化为红黑树的阈值static final intTREEIFY_THRESHOLD = 8;// 由红黑树转化为链表的阈值static final intUNTREEIFY_THRESHOLD = 6;// 转化为红黑树的表的最小容量static final intMIN_TREEIFY_CAPACITY = 64;// 每次进行转移的最小值private static final intMIN_TRANSFER_STRIDE = 16;// 生成sizeCtl所使用的bit位数private static intRESIZE_STAMP_BITS = 16;// 进行扩容所允许的最大线程数private static final intMAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;// 记录sizeCtl中的大小所需要进行的偏移位数private static final intRESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;// 一系列的标识static final intMOVED = -1;// hash for forwarding nodesstatic final intTREEBIN = -2;// hash for roots of treesstatic final intRESERVED = -3;// hash for transient reservationsstatic final intHASH_BITS = 0x7fffffff;// usable bits of normal node hash//
/** Number of CPUS, to place bounds on some sizings */
// 获取可用的CPU个数static final intNCPU = Runtime.getRuntime().availableProcessors();//
/** For serialization compatibility. */
// 进行序列化的属性private static finalObjectStreamField[] serialPersistentFields = {newObjectStreamField("segments", Segment[].class),newObjectStreamField("segmentMask", Integer.TYPE),newObjectStreamField("segmentShift", Integer.TYPE) };// 表transient volatileNode[] table; // 下一个表private transient volatileNode[] nextTable; //
/**
* Base counter value, used mainly when there is no contention,
* but also as a fallback during table initialization
* races. Updated via CAS.
*/
// 基本计数private transient volatile longbaseCount; //
/**
* Table initialization and resizing control. When negative, the
* table is being initialized or resized: -1 for initialization,
* else -(1 + the number of active resizing threads). Otherwise,
* when table is null, holds the initial table size to use upon
* creation, or 0 for default. After initialization, holds the
* next element count value upon which to resize the table.
*/
// 对表初始化和扩容控制private transient volatile intsizeCtl;/**
* The next table index (plus one) to split while resizing.
*/
// 扩容下另一个表的索引private transient volatile inttransferIndex;/**
* Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
*/
// 旋转锁private transient volatile intcellsBusy;/**
* Table of counter cells. When non-null, size is a power of 2.
*/
// counterCell表private transientvolatileCounterCell[] counterCells;// views
// 视图private transientKeySetView keySet;private transientValuesView values;private transientEntrySetView entrySet; // Unsafe mechanicsprivate static finalsun.misc.Unsafe U;private static final longSIZECTL;private static final longTRANSFERINDEX;private static final longBASECOUNT;private static final longCELLSBUSY;private static final longCELLVALUE;private static final longABASE;private static final intASHIFT; static{try{ U = sun.misc.Unsafe.getUnsafe(); Class k = ConcurrentHashMap.class; SIZECTL = U.objectFieldOffset (k.getDeclaredField("sizeCtl")); TRANSFERINDEX = U.objectFieldOffset (k.getDeclaredField("transferIndex")); BASECOUNT = U.objectFieldOffset (k.getDeclaredField("baseCount")); CELLSBUSY = U.objectFieldOffset (k.getDeclaredField("cellsBusy")); Class ck = CounterCell.class; CELLVALUE = U.objectFieldOffset (ck.getDeclaredField("value")); Class ak = Node[].class; ABASE = U.arrayBaseOffset(ak);intscale = U.arrayIndexScale(ak);if((scale & (scale - 1)) != 0)throw newError("data type scale not a power of two"); ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); }catch(Exception e) {throw newError(e); } }}
```