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> {
        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 {
        /**
         * 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

详见上面ReentrantLock

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. Future submit(Callable task);//有返回值
    
    eg:
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    //Runnable接口
    executorService.execute(()-> {
            log.info("this is 没有返回值");
        });
    //Callable 接口
    Future 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()));
    
    

1.18 a

    

你可能感兴趣的:(2018-12-19 java多线程)