2018-12-19 java多线程

java学习

[toc]

第一章线程安全

1.1 ThreadLocal理解


/**
这是一个ThreadLoca的内部Map

涉及到3个类
Thread
ThreadLocal
ThreadLocal.ThreadLocalMap

关系:
一个Thread对象里面有一个ThreadLocal.ThreadLocalMap,相当于是一个线程就一个ThreadLocalMap对象.

这个ThreadLocalMap里面的key是ThreadLocal对象, value是传递进行来的值


**/

Thread.class里面
ThreadLocal.ThreadLocalMap threadLocals = null;
static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    }
/**
set 操作
**/
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
/**
get操作
**/
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
//通过当前线程,或者ThreadLocal
ThreadLocalMap getMap(Thread t) {
    //每一个线程 存一份ThreadLocal.ThreadLocalMap
    return t.threadLocals;
}

1.2 CAS

    代码块

1.3 AQS

LockSupport

    1.先说一下理解。 这个东西是一个许可。 就是 0/1 俩个信号量
    2.LockSupport.park() //获取许可
    3.LockSupport.unpark(Thread thread) //释放许可
    -------------------------------------------------    
    默认这个许可是被占用的。。
     public static void test1(){
        //许可默认是被占用的。。。
        LockSupport.park();
        System.out.println("线程一直处于阻塞状态。。");
    }
    
    
    ------------------------------------------------
     public static void test2(){
        //许可默认是被占用的。。。
        Thread thread = Thread.currentThread();
        //释放许可
        LockSupport.unpark(thread);
        //获取许可
        LockSupport.park();
        System.out.println("1.释放许可, 2,获取许可, 打印");
    }
    ------------------------------------------------
    public static void test3(){
        //LockSupport是不可重入 一个线程连续俩次 park 也会阻塞
        Thread thread = Thread.currentThread();
        //许可默认是被占用的。。。
        //释放许可
        LockSupport.unpark(thread);
        //得到许可
        LockSupport.park();
        
        System.out.println("可以打印");
        //再次获取许可。。失败
        LockSupport.park();
        System.out.println("不可以打印");
    }
    

ReentrantLock

    AQS核心是利用CAS的理论,结合双向队列(lock)和单向队列(Condition)来实现的。

1.4 volatile 线程安全吗?

    不安全的。还是存在i++的问题。

1.5 Callable 和 Runnable 区别

    /**
    Callable 是一个有返回值的的,一般结合Future使用。
    **/
    @FunctionalInterface
    public interface Callable<V> {
        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        V call() throws Exception;
    }
    
    /**
    Runnalbe 是一个没有返回值的,正常线程的使用。
    **/
    @FunctionalInterface
    public interface Runnable {
        void run();
    }


1.6 Future 阻塞, 超时设置

    Future.get();//线程阻塞的。
    
    //线程阻塞,等待一段时间,然后抛出异常
    Future.get(long time,TimeUtil util);
    

1.7 ExecutorService 四种

    代码块

1.8 停止一个线程

    停止一个线程

1.9 多线程之间的通信和协作

    

1.10 ReentrantLock

详见上面<a href='#1.2 CAS'>ReentrantLock</a>

1.11 SynchronizedMap

    

1.12 HashMap

    

1.13 HashTable

    

1.14 并发框架

CopyOnWriteArrayList

    CopyOnWriteArrayList

CountDownLatch

    CountDownLatch

1.15 并发容器

CountDownLatch

    CountDownLatch

CyclicBarrie

    

1.16 线程池

Executors

    这个是创建的线程池, 也就是相当于创建Thread 肯定里面需要的是Runnable接口来的实线啦。
    
    //1.创建一个线程
     ExecutorService es = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            es.submit(()->{
                System.out.println(Thread.currentThread().getId());
            });
        }
    
    //2.创建一个固定大小的线程池
    ExecutorService es = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            es.submit(()->{
                System.out.println(Thread.currentThread().getId());
            });
        }
    
    //3.创建一个缓冲池的线程池,根据系统的内存
    ExecutorService es = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            es.submit(()->{
                System.out.println(Thread.currentThread().getId());
            });
        }
    //4.创建一个可以调度的线程池,这个特殊,可以延迟执行。。
    ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
        for (int i = 0; i < 10; i++) {
            es.schedule(()->{
                log.info("{}",Thread.currentThread().getId());
            },new Random().nextInt(10),TimeUnit.SECONDS);
        }

ExecutorService

    执行线程的方法有俩个
    1.void execute(Runnable command);//没有返回值
    2.<T> Future<T> submit(Callable<T> task);//有返回值
    
    eg:
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    //Runnable接口
    executorService.execute(()-> {
            log.info("this is 没有返回值");
        });
    //Callable 接口
    Future<Integer> future = executorService.submit(()->{
        log.info("this is 有返回值");
        return 1;
    });
    Integer result = future.get();
    

ThreadPoolExecutor

    上面的是jdk为了方便定义的一些线程池,但是我们伟大的程序员怎么能不自己创建呢。。这个类就是自己创建线程池的源码。
    参数解释:
    corePoolSize:池中保留的线程数
    maximumPoolSize:池中最大的线程数
    keepAliveTime:当线程池中的线程大于corePoolSize时候,等待新任务之前的保留时间
    unit:上面的保留时间
    workQueue:工作队列,用于保留执行任务之前的任务。 LinkedBlockingQueue
        1.直接切换
        2.使用无界队列  LinkedBlockingQueue
        3.使用有界队列  ArrayBlockingQueue
    
    threadFactory:创建新线程的工厂 DefaultThreadFactory->new Thread()
    handler:拒绝策略 :线程池满啦,工作队列满啦。
        1.AbortPolicy 直接抛出异常 默认策略
        2.CallerRunsPolicy:用调用者所在的线程来执行任务;[没看懂]
        3.DiscardOldestPolicy 丢弃阻塞队列最前面任务,并且执行当前任务
        4.DiscardPolicy 丢弃任务
    
    Executors.newSingleThreadExecutor(); //里面的实现
    new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    
    

1.18 a

    
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容