concurrent 三

参考文章

线程池 

SingleThreadExecutor() :单例的线程池

FixedThreadPool():定长的线程池

CachedThreadPool():缓存线程池

ScheduledThreadPool():支持定时及周期性任务执行。

阿里开发规范手册中指出的问题:

SingleThreadExecutor()和FixedThreadPool()

SingleThreadExecutor()进入源码:主要是默认的实现

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

SingleThreadExecutor()和FixedThreadPool()底层都是实现的LinkedBlockingQueue队列的阻塞方法,当线程不够用的时候所有的Runnable对象就会在队列中排队。请求的堆积线程会消耗大量的内存,甚至会引发OOM。

CachedThreadPool()和ScheduledThreadPool()

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}

public ScheduledThreadPoolExecutor(int corePoolSize,
                                   ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), threadFactory);
}

 SynchronousQueue<Runnable>和DelayedWorkQueue()随着任务数的增加会创建无数的线程,最后OOM。

当我们使用线程池的时候,注意一下这些问题。

基本线程的创建:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
}

7个参数:

corePoolSize:核心线程的数量

maximumPoolSize:最大线程的数量,核心线程数 + 非核心线程数

keepAliveTime:非核心线程池空闲后最大存活时间,如果设置allowCoreThreadTimeOut = true,则会作用于核心线程

TimeUnit :存活的时间单位

workQueue:当线程都在工作时,采用何种队列储存请求的Runnable对象。

threadFactory:这个参数没啥意义,给线程取名字

handler:当线程异常后需要作出的反应。


锁:

参考文章

锁的类型:

    可重入锁:在执行对象中所有同步方法不用再次获得同类型的锁

    可中断锁:在等待获取锁过程中可中断

    公平锁:按照线程的到来的先后顺序获得锁

     读写锁:读锁可多线程一起读。写锁,只能一个线程操作,不可读

在加上数据库层面的 悲观锁和乐观锁

    悲观锁:使用悲观锁的时,数据库中的这个行记录是不可用的

    乐观锁:增加version字段,每次更改增加version值,通过判断version值来判断是否修改

    Lock: 可重入锁,可中断锁,可以设置是否为公平锁,

Lock lock = new ReentrantLock(true);

ReentrantLock是Lock的实现类,只有可重入的实现类。如果不传入true则默认是非公平锁。非公平锁效率更高。主要方法:

 void lock();获取锁,如果不可用则等待

void unlock():释放锁

 boolean tryLock(); 尝试获取锁,如果能获取则为true

boolean  tryLock(long time, TimeUnit unit) 时间约束,多长时间内能否获取锁

 void lockInterruptibly() :可打断锁,如果在获取锁的时候进入等待,则可用方法将现场打断放弃等待

在使用lock加锁的时候一定要在finally中释放锁,不然这个锁会一致被异常线程占用,别的线程不可用。

synchronized与Lock的区别:参考博客中的图

读写锁:

ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
readWriteLock.readLock().lock();
readWriteLock.writeLock().lock();
readWriteLock.readLock().unlock();
readWriteLock.writeLock().unlock();

最要的方法就是readLock和writerLocak

readLock获取读锁,当使用读锁的时候,线程可以并发执行。当使用写锁的时候,所有的线程都需要排队直到写锁释放。

如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。读锁和写锁是互斥的。

这篇文章主要是自己的学习过程中的一个总结,所以写的比较粗糙,不够仔细。推荐的两篇博客都写的挺好的,有兴趣可以看一下。

努力吧,皮卡丘。

猜你喜欢

转载自blog.csdn.net/yidan7063/article/details/80310695