当前位置 博文首页 > Empirefree:Java并发编程--基础进阶高级(完结)

    Empirefree:Java并发编程--基础进阶高级(完结)

    作者:Empirefree 时间:2021-06-27 18:27

    Java并发编程--基础进阶高级完整笔记。

    这都不知道是第几次刷狂神的JUC并发编程了,从第一次的迷茫到现在比较清晰,算是个大进步了,之前JUC笔记不见了,重新做一套笔记。

    参考链接:https://www.bilibili.com/video/BV1B7411L7tE


    csdn csdn csdn csdn csdn


    目录
    • ??1.多线程--基础内容
      • 1.Thread状态
      • 2.Synchronized
      • 3.Lock锁
      • 4.总结
    • ??2.八锁现象(synchronized、static)
      • 1.synchronized
      • 2.static synchronized
    • ??3.Java集合--安全性
    • ??4.高并发--辅助类
      • 1.countdownLatch
      • 2.cyclicbarrier
      • 3.semaphore
    • ??5.读写锁(ReadWriteLock)
    • ??6.线程池
      • 1.集合--队列(阻塞队列、同步队列)
      • 2.线程池基本概念(三大方法、七大参数、四种拒绝策略)
    • ??7.Stream(4个函数式接口、Lambda、异步回调)
      • 1.函数式接口
      • 2.Lambda表达式
      • 3.异步回调
    • ??8.单例模式
      • 1.饿汉模式(程序一启动就new,十分占内存)
      • 2.懒汉模式(DCL模式:双重检测,需要的时候才new)
    • ??9.Volatile和Atomic
    • ??10.Java中锁
      • 1.公平锁(FIFO):Lock锁可以自定义,synchronized
      • 2.非公平锁(允许插队):Lock锁可以自定义
      • 3.可重入锁(获取一个锁再获取其他锁不会造成死锁):lock锁和synchronized
      • 4.自旋锁:得不到就一直等待(Atomic.getAndIncrement底层就是自旋锁)
      • 5.死锁命令排查



    ??1.多线程--基础内容

    1.Thread状态

    ? 6种:新建、运行、阻塞、等待、超时等待、结束(可点击Thread查看源代码)

    public enum State {
            NEW,
    
            RUNNABLE,
    
            BLOCKED,
    
            WAITING,
    
            TIMED_WAITING,
    
            TERMINATED;
        }
    

    2.Synchronized
    • 非公平锁
    • 可重入锁,

    ? Synchronized:是非公平锁(不能保证线程获得锁的顺序,即线程不会依次排队去获取资源,而是争抢,但是结果一定是正确的),是可重入锁(已获得一个锁,可以再获得锁且不会造成死锁,比如synchronized内部可以再写个synchronized函数)

        /**
         * Author: HuYuQiao
         * Description: Synchronized实现方式(修饰函数即可)
         */
        class TicketSync{
            public int number = 50;
            //synchronized本质是队列,锁
            public synchronized void sale(){
                if(number > 0) {
                    System.out.println(Thread.currentThread().getName() + "获得了第" + number-- +"票");
                }
            }
        }
    

    3.Lock锁
    • 可重入锁

    • 公平还是不公平锁可以设置(默认不公平锁)

          /**
           * Creates an instance of {@code ReentrantLock} with the
           * given fairness policy.
           *
           * @param fair {@code true} if this lock should use a fair ordering policy
           */
          public ReentrantLock(boolean fair) {
              sync = fair ? new FairSync() : new NonfairSync();
          }
      

      Lock:加锁之后必须解锁,,否则其他线程就获取不到了,所以用try-catch-finally包起来。

        /**
         * Author: HuYuQiao
         * Description: Lock实现方式(加锁、解锁)
         */
        class TicketLock{
            Lock lock = new ReentrantLock();
            public int number = 50;
            public void sale(){
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "获得了第" + number-- +"票");
    
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    

    4.总结

    ? 在不加锁情况下,多线程会争抢,导致输出顺序、计算结果都会不一致(上面例子结果如果一样是因为只有3个线程,for循环即出错,因为number--这个函数本身不是线程安全的),所以就引入了锁的概念,synchronized,lock保证了输出顺序、计算结果的一致性。

    ? 虚假唤醒:在synchronized.wait与lock.condition.await唤醒线程时,是从await代码之后开始运行,所以为了保证能唤醒线程,需要用while语句将代码包含起来。

    ? 完整代码

    package com.empirefree.springboot;
    
    import lombok.extern.slf4j.Slf4j;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import sun.security.krb5.internal.Ticket;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @program: springboot
     * @description: 多线程
     * @author: huyuqiao
     * @create: 2021/06/26 14:26
     */
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @Slf4j
    public class ThreadTest {
        
        /**
         * Author: HuYuQiao
         * Description: Synchronized实现方式(修饰函数即可)
         */
        class TicketSync{
            public int number = 50;
            //synchronized本质是队列,锁
            public synchronized void sale(){
                System.out.println(Thread.currentThread().getName() + "获得了第" + number-- +"票");
    
            }
        }
        
        /**
         * Author: HuYuQiao
         * Description: Lock实现方式(加锁、解锁)
         */
        class TicketLock{
            Lock lock = new ReentrantLock();
            public int number = 50;
            public void sale(){
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "获得了第" + number-- +"票");
    
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    
        @Test
        public void testThread() {
    //        TicketSync ticket = new TicketSync();
            TicketLock ticket = new TicketLock();
            new Thread( () ->{
                for (int i = 0; i < 50; i++) {
                    ticket.sale();
                }
    
            },"ThreadA").start();
            new Thread(()->{
                for (int i = 0; i < 50; i++) {
                    ticket.sale();
                }
            },"ThreadB").start();
            new Thread(()->{
                for (int i = 0; i < 50; i++) {
                    ticket.sale();
                }
            },"ThreadC").start();
    
            for (int i = 0; i < 500; i++) {
                new Thread(() -> {
                    ticket.sale();
                }).start();
            }
        }
    }
    
    



    ??2.八锁现象(synchronized、static)

    即synchronized、static修饰的函数,执行顺序、输出结果。

    结果表明:

    ? 1.synchronized修饰的函数:会锁住对象(可以看成锁对象中某个方法),看起来代码会依次执行,而没有锁的方法即不受影响,一来就先执行

    ? 2.static synchronized修饰的函数:会锁住类.class(可以不同对象访问的都是同一个函数),所以2个对象访问自己的函数依然还是顺序执行.

    ? 3.一个有static,一个没有static:即一个锁类.class,另一个锁对象,不管是同一个对象还是不同对象,就都不需要等待了,不会顺序执行。

    1.synchronized

    ? 修饰函数会保证同一对象依次顺序执行()

    class Phone{
        //synchronized
        public synchronized void sendSms() {
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("sendSms");
        }
        public synchronized  void call() {
            System.out.println("call");
        }
    
        public void playGame(){
            System.out.println("playGame");
        }
    }
    
        public static void main(String[] args) {
            //Thread--代码执行顺序问题
            Phone phone = new Phone();
            new Thread(phone::sendSms, "A").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(phone::call, "B").start();
            new Thread(phone::playGame, "C").start();
        }
    

    2.static synchronized
    class PhoneStatic{
        //static synchronized
        public static synchronized void sendSmsStatic() {
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("sendSmsStatic");
        }
        public static synchronized  void callStatic() {
            System.out.println("callStatic");
        }
    }
    
        public static void main(String[] args) {
            PhoneStatic phoneStatic = new PhoneStatic();
            PhoneStatic phoneStatic2 = new PhoneStatic();
            new Thread(() ->{
                phoneStatic2.sendSmsStatic();
            }, "A").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() ->{
                phoneStatic2.callStatic();
            }, "B").start();
        }
    



    ??3.Java集合--安全性

            //集合安全性--list,set,map都非线程安全
            List<String> list = new Vector<>();
            List<String> list = Collections.synchronizedList(new ArrayList<>());
            List<String> list = new CopyOnWriteArrayList<>();
    
            Map<String, String> objectObjectHashMap = new ConcurrentHashMap<>();
            Map<Object, Object> objectObjectHashMap1 = Collections.synchronizedMap(new HashMap<>());
            //set底层就是map:无论hashset还是linkedhashset
            Set<String> set = Collections.synchronizedSet(new LinkedHashSet<>());
            Set<String> set = new CopyOnWriteArraySet<>();   
    



    ??4.高并发--辅助类

    ? 学习链接:https://www.cnblogs.com/meditation5201314/p/14395972.html

    1.countdownLatch

    Countdownlatch:减一操作,直到为0再继续向下执行

    package Kuangshen.JUC.Thread;
    
    import java.util.concurrent.CountDownLatch;
    
    public class countDownLatch {
        public static void main(String[] args) throws InterruptedException {
    
            final CountDownLatch countDownLatch = new CountDownLatch(5);
    
            for (int i = 0; i < 5; i++) {
                new Thread(() -> {
                    System.out.println(Thread.currentThread().getName() + "get out");
                    countDownLatch.countDown();
                    }, String.valueOf(i)).start();
            }
            countDownLatch.await(); //等待上述执行完毕再向下执行
            System.out.println("close door");
        }
    }
    

    2.cyclicbarrier

    Cyclicbarrier:+1操作,对于每个线程都自动+1并等待,累计到规定值再向下执行,

    package Kuangshen.JUC.Thread;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    /**
     * @author :Empirefree
     * @description:TODO
     * @date :2021/2/10 10:56
     */
    public class cyclicbarrier {
        public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
            //CyclicBarrier里面是容量 + runnable
            final CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () ->{
                System.out.println("不断增加到7即向后执行,与countdownlatch相反");
            }
           );
    
            /*对于指派的局部变量,lambda只能捕获一次 ,故而需定义成final(int内部定义就是final),而且线程中,
            不能对局部变量进行修改,如需要修改,需定义成原子类atomic
            */
            for (int i = 0; i < 7; i++) {
                int finalI = i;
                new Thread(() ->{
                    System.out.println(finalI);
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
    
                }).start();
            }
        }
    
    }
    

    3.semaphore

    semaphore:对于规定的值,多个线程只规定有指定的值能获取,每次获取都需要最终释放,保证一定能互斥执行

    package Kuangshen.JUC.Thread;
    
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author :Empirefree
     * @description:TODO
     * @date :2021/2/10 15:24
     */
    public class semaphore {
        public static void main(String[] args) {
            final Semaphore semaphore = new Semaphore(3);
    
            for (int i = 0; i < 60; i++) {
                new Thread(() -> {
                    try {
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName() + "抢到车位");
                        TimeUnit.SECONDS.sleep(2);
                        System.out.println(Thread.currentThread().getName() + "离开车位");
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        semaphore.release();
                    }
                }).start();
            }
        }
    }
    



    ??5.读写锁(ReadWriteLock)

    ? ReadWriteLock也是多线程下的一种加锁方式,下面列出ReadWriteLock和synchronized对多线程下,保证读完之后在写的实现方式

    //读写锁 :写只有一个线程写,写完毕后 可以多个线程读
    MyCache myCache = new MyCache();
    int num = 6;
    for (int i = 1; i < num; i++) {
        int finalI = i;
        new Thread(()->{
            myCache.write(String.valueOf(finalI),String.valueOf(finalI));
    
        },String.valueOf(i)).start();
    }
    for (int i = 1; i < num; i++) {
        int finalI = i;
        new Thread(()->{
            myCache.read(String.valueOf(finalI));
        },String.valueOf(i)).start();
    }
    
    class MyCache{
        private volatile Map<String,String> map = new HashMap<>();
        private ReadWriteLock lock = new ReentrantReadWriteLock();
        //存,写
        public void write(String key,String value){
            lock.writeLock().lock();    //写锁
            try {
    
                System.out.println(Thread.currentThread().getName()+"线程开始写入");
                map.put(key,value);
                System.out.println(Thread.currentThread().getName()+"线程开始写入ok");
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                lock.writeLock().unlock();
            }
        }
        //取,读
        public void read(String key){
            lock.readLock().lock();     //读锁
            try {
    
                System.out.println(Thread.currentThread().getName()+"线程开始读取");
                map.get(key);
                System.out.println(Thread.currentThread().getName()+"线程读取ok");
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                lock.readLock().unlock();
            }
        }
    
    
        //存,写
        public synchronized void writeSync(String key,String value){
            try {
                System.out.println(Thread.currentThread().getName()+"线程开始写入");
                map.put(key,value);
                System.out.println(Thread.currentThread().getName()+"线程开始写入ok");
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        //取,读
        public void readSync(String key){
            try {
                System.out.println(Thread.currentThread().getName()+"线程开始读取");
                map.get(key);
                System.out.println(Thread.currentThread().getName()+"线程读取ok");
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    



    ??6.线程池

    1.集合--队列(阻塞队列、同步队列)

    • 阻塞队列:blockingQueue(超时等待--抛弃,所以最后size=1)

              //阻塞队列
              ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
              arrayBlockingQueue.offer("a", 2, TimeUnit.SECONDS);
              arrayBlockingQueue.offer("a", 2, TimeUnit.SECONDS);
              System.out.println("超时等待==" + arrayBlockingQueue.size());
      
    • 同步队列:synchronizeQueue(类似于生产者消费者)

              //同步队列
              SynchronousQueue<String> synchronousQueue = new SynchronousQueue<>();
              new Thread(()->{
                  try {
                      System.out.println(Thread.currentThread().getName()+"put 01");
                      synchronousQueue.put("1");
                      System.out.println(Thread.currentThread().getName()+"put 02");
                      synchronousQueue.put("2");
                      System.out.println(Thread.currentThread().getName()+"put 03");
                      synchronousQueue.put("3");
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }).start();
              new Thread(()->{
                  try {
                      System.out.println(Thread.currentThread().getName()+"take"+synchronousQueue.take());
                      System.out.println(Thread.currentThread().getName()+"take"+synchronousQueue.take());
                      System.out.println(Thread.currentThread().getName()+"take"+synchronousQueue.take());
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }).start();
      

    2.线程池基本概念(三大方法、七大参数、四种拒绝策略)
    • 三大方法:newSingleThreadExecutro(单个线程),newFixedThreadPool(固定大小线程池),newCachedThreadPool(可伸缩)

       ExecutorService threadPool = Executors.newSingleThreadExecutor();
              ExecutorService threadPool2 = Executors.newFixedThreadPool(5);
              ExecutorService threadPool3 = Executors.newCachedThreadPool();
      
    • 七大参数:

      ThreadPoolExecutor(int corePoolSize,  //核心线程池大小
                                int maximumPoolSize, //最大的线程池大小(当阻塞队列满了就会打开)
                                long keepAliveTime,  //(空闲线程最大存活时间:即最大线程池中有空闲线程超过这个时间就会释放线程,避免资源浪费)
                                TimeUnit unit, //超时单位
                                BlockingQueue<Runnable> workQueue, //阻塞队列
                                ThreadFactory threadFactory, //线程工厂 创建线程的 一般不用动
                                RejectedExecutionHandler handler //拒绝策略
      
      
    • 四种拒绝策略:

      new ThreadPoolExecutor.AbortPolicy: // 该 拒绝策略为:银行满了,还有人进来,不处理这个人的,并抛出异常
      new ThreadPoolExecutor.CallerRunsPolicy(): // //该拒绝策略为:哪来的去哪里 main线程进行处理
      new ThreadPoolExecutor.DiscardPolicy(): //该拒绝策略为:队列满了,丢掉异常,不会抛出异常。
      new ThreadPoolExecutor.DiscardOldestPolicy(): //该拒绝策略为:队列满了,尝试去和最早的进程竞争,不会抛出异常
      



    ??7.Stream(4个函数式接口、Lambda、异步回调)

    1.函数式接口

    ? 学习链接:https://www.cnblogs.com/meditation5201314/p/13693089.html


    2.Lambda表达式

    ? 学习链接:https://www.cnblogs.com/meditation5201314/p/13651755.html


    3.异步回调
            //异步回调--无返回值
            CompletableFuture<Void> future = CompletableFuture.runAsync(() ->{
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "....");
            });
            System.out.println("begin");
            System.out.println(future.get());
            System.out.println("end");
    
            //异步回调--有返回值
            CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() ->{
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return 3;
            });
            System.out.println("begin");
            System.out.println(future2.get());
            System.out.println(future2.whenComplete((result, error) ->{
                System.out.println("返回结果:" + result);
                System.out.println("错误结果" + error);
            }).exceptionally(throwable -> {
                System.out.println(throwable.getMessage());
                return 502;
            }).get());
            System.out.println("end");
    



    ??8.单例模式

    1.饿汉模式(程序一启动就new,十分占内存)
    /**
     * @program: untitled
     * @description: 单例模式
     * @author: huyuqiao
     * @create: 2021/06/27 14:44
     */
    
    public class SingleModel {
    
        /*
         * 可能会浪费空间
         * */
        private byte[] data1 = new byte[1024*1024];
        private byte[] data2 = new byte[1024*1024];
        private byte[] data3 = new byte[1024*1024];
        private byte[] data4 = new byte[1024*1024];
        private static final SingleModel hugrySingle = new SingleModel();
        private SingleModel(){
    
        }
        public static SingleModel getInstance(){
            return hugrySingle;
        }
    }
    
    

    2.懒汉模式(DCL模式:双重检测,需要的时候才new)

    1.第一层if没有加锁,所以会有多个线程到达if
    2.如果内部new对象指令重排,就会导致有些线程认为lazyManModel有对象,所以会直接返回lazyManModel(实际为null)
    3.所以需要加上valitile防止指令重排

    /**
     * @program: untitled
     * @description: 懒汉式
     * @author: huyuqiao
     * @create: 2021/06/27 15:06
     */
    
    public class LazyManModel {
        private volatile static LazyManModel lazyManModel;
        private LazyManModel(){
            System.out.println(Thread.currentThread().getName() + "...");
        }
    
        //DCL懒汉式:双重检测锁--实现效果,只有为空的才null,否则不用null,所以需要2重if判断。
        public static LazyManModel getInstance(){
            if (lazyManModel == null){
                synchronized (LazyManModel.class){
                    if (lazyManModel == null){
                        lazyManModel = new LazyManModel();
                    }
                }
            }
            return lazyManModel;
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(() ->{
                    LazyManModel.getInstance();
                }).start();
            }
        }
    }
    



    ??9.Volatile和Atomic

    ? 学习笔记:https://www.cnblogs.com/meditation5201314/p/13707590.html

    ?

    ??10.Java中锁

    1.公平锁(FIFO):Lock锁可以自定义,synchronized
    2.非公平锁(允许插队):Lock锁可以自定义
    3.可重入锁(获取一个锁再获取其他锁不会造成死锁):lock锁和synchronized
    4.自旋锁:得不到就一直等待(Atomic.getAndIncrement底层就是自旋锁)
    import java.util.Collections;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.atomic.AtomicReference;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @program: untitled
     * @description: spinlock
     * @author: huyuqiao
     * @create: 2021/06/27 15:40
     */
    
    public class SpinLockTest {
        public static void main(String[] args) throws InterruptedException {
    
            //使用CAS实现自旋锁
            SpinlockDemo spinlockDemo=new SpinlockDemo();
            new Thread(()->{
                spinlockDemo.myLock();
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    spinlockDemo.myUnlock();
                }
            },"t1").start();
    
            TimeUnit.SECONDS.sleep(1);
    
    
            new Thread(()->{
                spinlockDemo.myLock();
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    spinlockDemo.myUnlock();
                }
            },"t2").start();
        }
    }
    
    class SpinlockDemo {
    
        // 默认
        // int 0
        //thread null
        AtomicReference<Thread> atomicReference=new AtomicReference<>();
    
        //加锁
        public void myLock(){
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+"===> mylock");
    
            //自旋锁--为空则返回true,否则返回false
            while (!atomicReference.compareAndSet(null,thread)){
                System.out.println(Thread.currentThread().getName()+" ==> .自旋中~");
            }
        }
    
    
        //解锁
        public void myUnlock(){
            Thread thread=Thread.currentThread();
            System.out.println(thread.getName()+"===> myUnlock");
            atomicReference.compareAndSet(thread,null);
        }
    
    }
    
    
    5.死锁命令排查
    jps -l
    jstack 进程号
    
    bk
    下一篇:没有了