多线程/线程池/锁相关面试总结

多线程(线程池)
启动线程调用start() 方法,run()方法是线程启动后须要执行的方法。

1. 继承thread类
2. 实现runnable 接口
3. 实现callable 接口(call()方法,有返回值经过future对象的get()方法能够获取返回值,get()方法会阻塞,直到任务结果返回)
Callable 和 Future接口的区别
1. Callable规定的方法是call(),而Runnable规定的方法是run()。 
2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。  
3. call()方法可抛出异常,而run()方法是不能抛出异常的。 
4. 运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。 
5. 它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 
6. 经过Future对象可了解任务执行状况,可取消任务的执行,还可获取任务执行的结果。 
7. Callable是相似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务
线程池:

线程池类继承图(1).jpg

经常使用的是 ThreadPoolExecutor 类 自定义 corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit, BlockingQueue数据库

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

线程池公式 :缓存

maximumPoolSize = 2 * corePoolSize = 4 * cpu线程数
Executors线程池工具类:
Executors.new SingleThreadPoolExecutor(); 最大线程数为1
Executors.new FixedThreadPoolExecutor(5) :核心线程数 = 最大线程数
Executors.new CachedThreadPoolExecutor() :缓存线程池
Executors.new ScheduledThreadPoolExecutor(5) :延迟/周期性线程池

single和fixed阻塞队列最大为 Interger.MAX_VALUE [2的31次方];
cached 和scheduled 最大线程数为 Interger.MAX_VALUE [2的31次方];多线程

===========================================================================dom

锁 :

锁分类:
  • 可重入锁:Synchronized和ReentrantLook都是可重入锁,锁的可重入性标明了锁是针对线程分配方式而不是针对方法。例如调用Synchronized方法A中能够调用Synchronized方法B,而不须要从新申请锁。
  • 读写锁:按照数据库事务隔离特性的类比读写锁,在访问统一个资源(一个文件)的时候,使用读锁来保证多线程能够同步读取资源。ReadWriteLock是一个读写锁,经过readLock()获取读锁,经过writeLock()获取写锁。
  • 可中断锁:可中断是指锁是能够被中断的,Synchronized内置锁是不可中断锁,ReentrantLock能够经过lockInterruptibly方法中断显性锁。例如线程B在等待等待线程A释放锁,可是线程B因为等待时间过久,能够主动中断等待锁。
  • 公平锁:公平锁是指尽可能以线程的等待时间前后顺序获取锁,等待时间最久的线程优先获取锁。synchronized隐性锁是非公平锁,它没法保证等待的线程获取锁的顺序,ReentrantLook能够本身控制是否公平锁。
两种锁的底层实现:
  • Synchronized:底层使用指令码方式来控制锁的,映射成字节码指令就是增长来两个指令:monitorenter和monitorexit。当线程执行遇到monitorenter指令时会尝试获取内置锁,若是获取锁则锁计数器+1,若是没有获取锁则阻塞;当遇到monitorexit指令时锁计数器-1,若是计数器为0则释放锁。
  • Lock:底层是CAS乐观锁,依赖AbstractQueuedSynchronizer类,把全部的请求线程构成一个CLH队列。而对该队列的操做均经过Lock-Free(CAS)操做。
Synchronized和Lock比较
  • Synchronized是关键字,内置语言实现,Lock是接口。
  • Synchronized在线程发生异常时会自动释放锁,所以不会发生异常死锁。Lock异常时不会自动释放锁,因此须要在finally中实现释放锁。
  • Lock是能够中断锁,Synchronized是非中断锁,必须等待线程执行完成释放锁。
  • Lock可使用读锁提升多线程读效率。
sychronized :
Lock :使用Lock必须在try…catch…块中进行,而且将释放锁的操做放在finally块中进行
ReentrantLock: (用法lock.tryLock() )
// 获取锁  
    void lock()   

    // 若是当前线程未被中断,则获取锁,能够响应中断  
    void lockInterruptibly()   

    // 返回绑定到此 Lock 实例的新 Condition 实例  
    Condition newCondition()   

    // 仅在调用时锁为空闲状态才获取该锁,能够响应中断  
    boolean tryLock()   

    // 若是锁在给定的等待时间内空闲,而且当前线程未被中断,则获取锁  
    boolean tryLock(long time, TimeUnit unit)   

    // 释放锁  
    void unlock()

tryLock()方法是有返回值的,它表示用来尝试获取锁,若是获取成功,则返回true;若是获取失败(即锁已被其余线程获取),则返回false,也就是说,这个方法不管如何都会当即返回(在拿不到锁时不会一直在那等待)。
tryLock(long time, TimeUnit unit)方法和tryLock()方法是相似的,只不过区别在于这个方法在拿不到锁时会等待必定的时间,在时间期限以内若是还拿不到锁,就返回false,同时能够响应中断。若是一开始拿到锁或者在等待期间内拿到了锁,则返回true。异步

ReentrantReadWriteLock : 读写锁 (用法 lock.readLock().lock())
要点 : 共享读,独占写
//返回用于读取操做的锁  
Lock readLock()   
//返回用于写入操做的锁  
Lock writeLock()

代码示例 :工具

// 读数据
    public void get() {
        // 加读锁
        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to read data!");
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println(Thread.currentThread().getName() + " have read data :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放读锁
            lock.readLock().unlock();
        }
    }

    // 写数据
    public void put(Object data) {
        // 加写锁
        lock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to write data!");
            Thread.sleep((long) (Math.random() * 1000));
            this.data = data;
            System.out.println(Thread.currentThread().getName() + " have write data: " + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放写锁
            lock.writeLock().unlock();
        }

    }
}
相关文章
相关标签/搜索