一、线程安全问题
①当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。
②临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性
③原子操作:不可分割的多步操作,被视为一个整体,其顺序和步骤不可打乱或缺省。
二、线程的状态?
①New ②Runable ③waiting ④Time-Waiting ⑤Blocked ⑥Terminated
三、如何保证线程安全
①使用同步代码块
synchronized(临界资源对象){//对临界资源对象加锁
//代码(原子操作)
}
注意:
每个对象都有一个互斥锁标记,用来分配给线程的
只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块
线程退出同步代码块时,会释放相应的互斥锁标记
②使用同步方法
synchronized 返回值类型 方法名称(形参列表o){ //对当前对象this加锁
//代码(原子操作)
}
注意:
只有拥有对象互斥锁标记的线程,才能进入该对象加锁的同步方法中。
线程退出同步方法时,会释放相应的互斥锁标记。
四、线程安全类有哪些?
①Hashtable
②StringBuffer
③Vector
Hashtable和hashmap的区别?
1.线程安全 2.key和value是否允许null
3.效率高低
HashMap的底层实现原理?
是线程不安全的,但效率高,key和value都可以是空对象
存储结构主要是数组加链表,在java 8中的实现增加了红黑树,按照key的hash值进行判断,如果hash值相同,就按照equals方法判断,如果equals不同,就存入链表,如果hash不同,就直接存放数组,如何hash冲突的元素很多。达到8个的时候,会把链表转化成红黑树,低于6个的时候,会退回链表。
五、wait方法和Sleep方法的区别?
①wait属于Object类,sleep属于Thread类
②wait会释放锁资源,sleep不会释放锁资源
③wait需要notify和notifyAll唤醒,sleep时间到了会自动唤醒
④Wait必须使用在同步代码块或者同步方法中,sleep可以在任何地方使用。
六、notify和notifyAll的区别?
1.notify随机唤醒等待队列中的某个线程,
2.notifyAll唤醒等待队列中所有的线程。
七、死锁
①当第一个线程拥有A对象锁标记,并等待B对象锁标记,同时第二个线程拥有B对象锁标记,并等待A对象锁标记时,产生死锁
②一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已经拥有的锁标记,由此可能造成死锁。
八、创建线程池的方式
①固定长度的线程池
ExecutorService executorService=Executors.newFixedThreadPool(3);
②可变长度的线程池,如果存在空闲的线程,则不会创建新的。
ExecutorService executorService=Executors.newCachedThreadPool();
③创建单一线程池
ExecutorService executorService=Executors.newSingleThreadExecutor();
④创建定长延迟线程池
ScheduledExecutorService executorService=Executors.newScheduledThreadPool(3);
⑤ExecutorService实现类创建.ThreadPoolExecutor
ArrayBlockingQueue blockingQueue=new ArrayBlockingQueue(2);
ExecutorsService executorService=new ThreadPoolExecutor(3,5,30,TimeUnit.SECONDS,blockingQueue);
九、submit和execute区别?
1.submit可以提交runnable和callbale类型的任务,而execute执行提交Runable类型的任务