JUC并发编程总结(二)

点我跳转至JUC并发编程总结(一)

JUC并发编程总结(二)

  • 函数接口、流式计算
    • 四大函数式接口
    • 流式计算stream
  • Forkjoin
    • 工作模型
    • 注意事项
  • 异步
  • JMM到单例模式
    • 1. 对Volatile关键字的理解
    • 2. JMM:java内存模型
    • 3. 彻底玩转单例模式
  • CAS:比较并交换
    • 1. 理解CAS
    • 2. 原子引用
  • 各种锁
    • 公平锁、非公平锁
    • 可重入锁(递归锁)
    • 自旋锁
    • 死锁问题排查方案
  • AQS(AbstractQueuedSynchronizer)
    • 手动写一个锁。
  • Reference

  • 前言:此总结更接近于使用和回顾juc内容。如果需要深入研究底层,请看源码或者官网文档。

函数接口、流式计算

四大函数式接口

  1. Predicate函数式接口,断言型,返回true/false
  2. Function函数式接口,函数型,有输入输出。
  3. Consumer函数式接口,消费型,有输入输出。
  4. Supplier函数式接口,供给型,无输入有输出。
  • Predicate,重写test方法。提供两种效果一样的实现方式。
     Predicate predicate =new Predicate<String>() {
         @Override
         public boolean test(String o) {
             return false;
         }
     };
     Predicate predicate1=(str)->{return false;};
     System.out.println(predicate.test("0"));
    
  • Function,重写apply方法。提供两种效果一样的实现方式。第一个是传入参数,第二个是返回值。
     Function function =new Function<Integer,String> (){
         @Override
         public String apply(Integer o) {
             return o+"";
         }
     };
     Function function1=(str)->{return str;};
     System.out.println(function1.apply(5));
    
  • Consumer,重写accept方法。提供两种效果一样的实现方式。
    Consumer consumer=new Consumer<String>() {
        @Override
        public void accept(String o) {
            System.out.println(o);
        }
    };
    Consumer consumer1 =(str)->{ System.out.println(str);};
    consumer1.accept("消费者接口被调用");
    
  • Supplier,重写get方法。提供两种效果一样的实现方式。
     Supplier supplier=new Supplier<Integer>() {
         @Override
         public Integer get() {
             return null;
         }
     };
     Supplier supplier1 =()->{System.out.println("接口被调用"); return "aaa";};
     System.out.println( supplier1.get());
    

流式计算stream

  • 流式计算常用于计算大的数据量,效率非常高。是常规计算效率的十倍。
  • 示例:
        public static void main(String[] args) {
            List<User> list =new ArrayList<>();
            for (int i = 0; i <6 ; i++) {
                User user=new User(i,i+"娃",i);
                list.add(user);
            }
            list.stream()
                    .filter(u->{return u.getId()%2==0;})
                    .filter(u->{return u.getAge()>2;})
                    .map(u->{return u.getName().replace("娃","wa");})
                    .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
                    .limit(1)
                    .forEach(System.out::println);
        }
    

Forkjoin

工作模型

JUC并发编程总结(二)_第1张图片

注意事项

  • 使用
  1. 使用ForkJoinPool来执行分段任务。
  2. 计算任务forkJoinPool.submit(task)
  3. 计算类要继承ForkJoinTask,重新compute方法。
  • 示例 :分段计算任务。
    class ForkJoinDemo extends RecursiveTask<Long>{
        private Long temp =1000L;
        private Long start;
        private Long end;
    
        public ForkJoinDemo(Long start, Long end) {
            this.start = start;
            this.end = end;
        }
        @Override
        protected Long compute() {
           if (end-start<temp){
               Long sum=0L;
               for (Long i = start; i <=end ; i++) {
                   sum+=i;
               }
               return sum;
           }else {
               long middle=(start+end)/2;
               ForkJoinDemo task1=new ForkJoinDemo(start,middle);
               task1.fork();
               ForkJoinDemo task2=new ForkJoinDemo(middle+1,end);
               task2.fork();
               return task1.join()+task2.join();
           }
        }
    }
    
    public class Demo08Forkjoin {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            Long start = System.currentTimeMillis();
            //使用forkjoin
            ForkJoinPool forkJoinPool=new ForkJoinPool();
            ForkJoinTask task =new ForkJoinDemo(0L,10000000L);
            ForkJoinTask submit =forkJoinPool.submit(task);
            Long sum = (Long) submit.get();
    
            Long end = System.currentTimeMillis();
            System.out.println(end-start+":"+sum);
    
            Long start1 = System.currentTimeMillis();
            //不使用
            Long sum1=0L;
            for (Long i = 0L; i <=10000000L ; i++) {
                sum1+=i;
            }
            Long end1 = System.currentTimeMillis();
            System.out.println(end1-start1+":"+sum1);
        }
    }
    

异步

  • CompletableFuture和函数接口一样也提供了supplyAsync()/runAsync等方法。使用时选择正确的方法。
  • 像JS和Promise那样执行异步任务。
            CompletableFuture<Integer> completableFuture=CompletableFuture.supplyAsync(()->{
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("异步任务执行完毕");
                return 500;
            });
            System.out.println("主线程任务");
            completableFuture.get();
    
           int a =  completableFuture.whenComplete((t,u)->{
                System.out.println("正确执行时返回结果:"+t);
                System.out.println("正确执行时返回结果:"+u);
            }).exceptionally((e)->{
                return  233;
            }).get();
           
           System.out.println(a);
    

JMM到单例模式

1. 对Volatile关键字的理解

  • volatile是java虚拟机提供的轻量级同步机制。
  1. 保证可见性
  2. 不保证原子性
  3. 禁止指令重排
  • 通知其他线程变量已经更改。

2. JMM:java内存模型

JUC并发编程总结(二)_第2张图片
JUC并发编程总结(二)_第3张图片

  • 保证可见性:
    JUC并发编程总结(二)_第4张图片
  • 不保证原子性 :多个线程修改带有volatile关键字的变量时仍然会出问题。
  • 禁止指令重排 (了解更多请查看相关文档)
  1. 保证特定操作有序
  2. 保证变量内存可见性。

3. 彻底玩转单例模式

JUC并发编程总结(二)_第5张图片

CAS:比较并交换

1. 理解CAS

JUC并发编程总结(二)_第6张图片
JUC并发编程总结(二)_第7张图片
JUC并发编程总结(二)_第8张图片

  • 缺点
  1. 循环耗时
  2. 一次保证一个共享变量原子性
  3. ABA问题
    JUC并发编程总结(二)_第9张图片

2. 原子引用

JUC并发编程总结(二)_第10张图片

各种锁

公平锁、非公平锁

  • 关键是能不能插队的问题
  • 可重入锁构造方法
    JUC并发编程总结(二)_第11张图片

可重入锁(递归锁)

  • 得到大门锁,自然得到房间锁。
  • 注意sms里面调用了call()JUC并发编程总结(二)_第12张图片

自旋锁

JUC并发编程总结(二)_第13张图片

死锁问题排查方案

  1. 使用jps- a进行进程号定位:
    JUC并发编程总结(二)_第14张图片
  2. 使用jstack 进程号进行定位
    JUC并发编程总结(二)_第15张图片

AQS(AbstractQueuedSynchronizer)

  • 此类事锁的实现原理。

手动写一个锁。

public class Demo11AQS {
    public static void main(String[] args) throws InterruptedException {
        final Integer[] sum = {0};
        Lock lock =new MyLock();
        Thread[] a= new Thread[500];
        for (int j = 0; j <500 ; j++) {
          a[j] = new Thread(()->{
                lock.lock();
                sum[0]++;
                lock.unlock();
            });
          a[j].start();
        }
        for (Thread item:a){
            item.join();
        }
        System.out.println(sum[0]);
    }
   static void add(Integer a,Integer b){
        a=a+b;
   }
}

class MyLock implements Lock {

    private Sync sync =new Sync();

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return null;
    }
    private class Sync extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryAcquire(int arg) {
            assert arg==1;
            if (compareAndSetState(0,1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        @Override
        protected boolean tryRelease(int arg) {
            assert arg==1;
            if (! isHeldExclusively()) try {
                throw new IllegalAccessException();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        @Override
        protected boolean isHeldExclusively() {
            return getExclusiveOwnerThread()==Thread.currentThread();
        }
    }
}

Reference

  1. https://www.jianshu.com/p/c366c9238bb8

你可能感兴趣的:(java)