美文网首页
多线程(juc随笔)1

多线程(juc随笔)1

作者: 云中人山 | 来源:发表于2018-12-18 09:34 被阅读3次

    据说在java 1.5之前,如果涉及到多线程的场景,大家只能使用从1.0开始就存在的一个接口: Runnable,
    或者说使用实现了Runnabel接口的Thread类


    在1.5版本时,Doug Lea 在版本中编写了java.util.concurrent ,让线程的使用变得更加简单
    笔者使用的jdk版本为1.9,但是考虑到1.9使用的人不多,在这里还是讨论1.8版本的内容。
    在这个版本的java.util.concurrent包内,大致分了一下类:

    juc.png

    atomic

    atomic包内包含有一系列支持原子操作的类,最常用的一般为AtomicBooleanAtomicIntegerAtomicLong
    在这些类中,涉及到值的操作,都是调用的Unsafe中对应方法(或者是VarHandle中对应方法,参见Unsafe -> VarHandle

    以AtomicInteger为例,这里的addAndGet方法实际调用的是VarHandle#getAndAdd

    /**
         * Atomically adds the given value to the current value,
         * with memory effects as specified by {@link VarHandle#getAndAdd}.
         *
         * @param delta the value to add
         * @return the updated value
         */
        public final int addAndGet(int delta) {
            return U.getAndAddInt(this, VALUE, delta) + delta;
        }
    

    locks

    locks包内包含锁相关的类和接口,比如最核心的lock接口,其主要方法有lock()tryLock()unlock(),这里不做过多介绍

    Lock接口

    locks包内包含 LockCondition 相关内容

    其中Lock接口

    * {@code Lock} implementations provide more extensive locking
     * operations than can be obtained using {@code synchronized} methods
     * and statements.  They allow more flexible structuring, may have
     * quite different properties, and may support multiple associated
     * {@link Condition} objects.
    

    简单来说,Lock接口实际上是对 synchronized的一个扩展,并提供了更加灵活的操作,比如其tryLock()方法,并且支持Condition 对象,关于Condition,我们稍后会进行讨论

    Lock接口的基本方法有:

    void lock();
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
    

    ReadWriteLock接口

    在实际的场景中,大部分的情况下我们是读取数据,并不是修改或者写入数据,而传统的synchronized关键字并不支持对读写场景的区分,在jdk1.5之后也加入了ReadWriteLock接口,提供读写锁的支持

    每个读写锁由读锁和写锁构成:

    public interface ReadWriteLock {
        /**
         * Returns the lock used for reading.
         *
         * @return the lock used for reading
         */
        Lock readLock();
    
        /**
         * Returns the lock used for writing.
         *
         * @return the lock used for writing
         */
        Lock writeLock();
    }
    

    必须注意的是,所有实现ReadWriteLock实现必须保证,成功获取readLock的线程将看到在先前释放writeLock所做的所有更新

    以下内容来自维基百科:

    读写锁是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁。[[1]](https://zh.wikipedia.org/wiki/%E8%AF%BB%E5%86%99%E9%94%81#cite_note-Hamilton-1)多读者锁,[2],“push lock”[3]) 用于解决读写问题。读操作可并发重入,写操作是互斥的。

    线程池相关

    Executor

    一个Executor应该能执行被提交的Runnable方法,并且这个接口将任务提交和任务执行之间解耦了

    实际上,许多Executor的实现类会对任务执行进行调度,并将任务序列化后交给第二个executor,如下所示

    import java.util.ArrayDeque;
    import java.util.Queue;
    import java.util.concurrent.Executor;
    
    public class SerialExecutor implements Executor {
        final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
        final Executor executor;
        Runnable active;
    
        SerialExecutor(Executor executor) {
            this.executor = executor;
        }
        @Override
        public synchronized void execute(final Runnable r) {
            tasks.offer(new Runnable() {
                @Override
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (active == null) {
                scheduleNext();
            }
        }
    
        protected synchronized void scheduleNext() {
            if ((active = tasks.poll()) != null) {
                executor.execute(active);
            }
        }
    }
    

    Executors

    总的来说这个类是线程池的工厂类,提供了多种线程池的生成静态方法


    ExecutorService

    • ExecutorService 继承了Executor接口,并且提供了 shutdown()方法来关闭线程池
    • Executor只能接受Runnable任务,而ExecutorService还能接受Callable任务
    • Executorsubmit()方法没有返回值,ExecutorService中提供了Future型的返回值

    Future

    Future代表一个异步计算的结果,并且提供了对应的方法来判断任务是完成还是取消了,也提供了等待任务完成的方法。

     * interface ArchiveSearcher { String search(String target); }
     * class App {
     *   ExecutorService executor = ...
     *   ArchiveSearcher searcher = ...
     *   void showSearch(final String target)
     *       throws InterruptedException {
     *     Future<String> future
     *       = executor.submit(new Callable<String>() {
     *         public String call() {
     *             return searcher.search(target);
     *         }});
     *     displayOtherThings(); // do other things while searching
     *     try {
     *       displayText(future.get()); // use future
     *     } catch (ExecutionException ex) { cleanup(); return; }
     *   }
     * }}
    

    相关文章

      网友评论

          本文标题:多线程(juc随笔)1

          本文链接:https://www.haomeiwen.com/subject/pulscqtx.html