JUC了解

JUC

第一节:什么是JUC ?

JUC就是java.util.concurrent工具包的简称。这是一个处理线程的工具包,在JDK1.5开始出现的。

第二节:进程和线程
2.1 简介
  • 进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
  • 线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
  • 一个程序至少一个进程,一个进程至少一个线程。
2.2 进程与线程间的区别
  • 地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。
  • 资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等。但是进程之间的资源是独立的。
  • 执行过程:每个独立的进程都有一个程序运行的入口,顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  • 线程是处理调度器的基本单位,但是进程不是。
  • 两者均可并发执行。
  • 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃后整个进程都死掉了。所以多进程要比多线程强壮。
  • 进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。通过如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
2.3 进程和线程的优缺点
  • 线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。
  • 进程执行开销大,但是能够很好的进行资源管理和保护。进程可以跨机器前移。
2.4 何时使用多进程,何时使用多进程

对资源的管理和保护要求高,不限制开销和效率时,使用多进程。要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。

拓展:Java真的可以开启线程吗?
 public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
	//不能开启,底层的C++,JAVA无法直接操作硬件
   private native void start0();
第三节:并发编程中的并发与并行
  • 并发(concurrency)(多线程操作同一个资源)

    1. CPU 一核,模拟出来多条线程,实际通过快速交换CPU的使用权限来实现的。
  • 并行(parallellism)(过个人一起行走)

    1. CPU多核,多个线程可以同时指向;线程池。
public static void main(String[] args) {
        //获取当前系统的CPU核数(CPU密集型,IO密集型)
        System.out.println(Runtime.getRuntime().availableProcessors());
    }

并发编程的本质:充分利用系统资源

第四节:线程的回顾
4.1 线程的状态
public enum State {
        /**
         * Thread state for a thread which has not yet started.
         * 新生
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         * 运行
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         * 阻塞
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         * 等待,死死的等
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         * 超时等待
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         * 终止
         */
        TERMINATED;
    }

4.2 wait和sleep的区别
  • 来自不同的类:wait ==> Object sleep == > thread
  • 关于锁的释放:wait会释放锁,sleep睡觉了会抱着锁睡,不释放锁。
  • 使用范围不同:wait必须在同步代码块中使用,sleep可以在任何地方使用。
  • 是否需要异常捕获:都需要

4.3 Synchronized 关键字

package com.seapp.lock;

import sun.security.mscapi.CPublicKey;

import java.util.concurrent.TimeUnit;

/**
 * @author seapp
 * @date 2021/6/10 17:10
 * 真正的多线程开发,降低耦合性,线程就是一个单独的资源类,没有任何的附属的操作
 */
public class SaleTicketDemo {

    public static void main(String[] args) {
        //并发,多线程操作同一资源类
        Ticket ticket = new Ticket();

        //学生A买票
        new Thread(()->{
            for (int i = 1; i <= 40 ; i++) {
                ticket.sale();
            }
        },"A").start();

        //学生B买票
        new Thread(()->{
            for (int i = 1; i <= 40 ; i++) {
                ticket.sale();
            }
        },"B").start();

        //学生A买票
        new Thread(()->{
            for (int i = 1; i <= 40 ; i++) {
                ticket.sale();
            }
        },"B").start();


    }

}


/**
 * 资源类
 */
class Ticket{

    //初始化变量
    private int num = 30;

    //卖票
    public synchronized void sale(){
        if(num >0){
            System.out.println(Thread.currentThread().getName() + "买到了" + num-- + "张票,剩余" + num);
        }

    }

}

4.4 lock

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

package com.seapp.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author seapp
 * @date 2021/6/10 17:39
 * <p>
 * lock锁的三部曲:
 * 1、new ReentrantLock();
 * 2. lock.lock();
 * 3. finally ==> lock.unlock();
 */
public class LockDemo {


    public static void main(String[] args) {
        //并发,多线程操作同一资源类
        Ticket02 ticket = new Ticket02();

        //学生A买票
        new Thread(() -> {
            for (int i = 1; i <= 50; i++) {
                ticket.sale();
            }
        }, "A").start();

        //学生B买票
        new Thread(() -> {
            for (int i = 1; i <= 50; i++) {
                ticket.sale();
            }
        }, "B").start();

        //学生A买票
        new Thread(() -> {
            for (int i = 1; i <= 50; i++) {
                ticket.sale();
            }
        }, "B").start();


    }

}


/**
 * 资源类
 */
class Ticket02 {


    //初始化变量
    private int num = 30;

    Lock lock = new ReentrantLock();

    //卖票
    public synchronized void sale() {
        lock.lock();
        try {
            if (num > 0) {
                System.out.println(Thread.currentThread().getName() + "买到了" + num-- + "张票,剩余" + num);
            }
        }finally {
            lock.unlock();
        }


    }
}
4.5 Synchronized和lock的区别
  1. Synchronized内置的Java关键字,Lock是一个Java类
  2. Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁。
  3. Synchronized 会自动释放锁,lock必须要手动释放锁!如果不释放锁,死锁。
  4. Synchronized 线程1(获取锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去。
  5. Synchronizecd可重入锁,不可以中断的,非公平。Lock,可重入锁,可以判断锁,非公平(可以自己设定)
  6. Synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码!
第七节:Callable在这里插入图片描述
  • 可以有返回值
  • 可以抛出异常值
  • 方法不同,run()/call()

在这里插入图片描述
在这里插入图片描述

package com.seapp.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author seapp
 * @date 2021/6/12 15:22
 */
public class CallableDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        new Thread(new Runnable()).start();
//        new Thread(new FutureTask<V>()).start();
//        new Thread(new FutureTask<V>( Callable)).start();
        //如何启动callable呢?
        MyThread myThread = new MyThread();
        FutureTask<Integer> futureTask = new FutureTask<>(myThread);
        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start();//两个线程调用该callable,但只执行了一次。被缓存了。

        //Callable返回结果的获取
        Integer integer = futureTask.get();//get方法可能是异步,会产生阻塞,需放在最后处理。
        System.out.println("integer = " + integer);


    }

}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("call方法被调用了");
        return 3;
    }
}
第八节:常用的辅助类
8.1 CountDownLatch

在这里插入图片描述

package com.seapp.sample;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author seapp
 * @date 2021/6/15 8:40
 */
public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        //设置countDownLatch初始化计数
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                System.out.println(" go out");
                //在异步线程中,每一个线程执行完进行减1操作。
                countDownLatch.countDown();
            }).start();
        }
        //等待,直到countDownLatch计数为0时,才执行下属方法。
        countDownLatch.await();
        System.out.println("执行完成了...");
    }

}
8.2 CyclicBarrier

在这里插入图片描述

package com.seapp.sample;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author seapp
 * @date 2021/6/15 9:15
 * 与CountDownLatch作用相同,当达到某种界定值时,执行对应的
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("集齐七龙族,神龙再现");
        });


        for (int i = 0; i < 7; i++) {
            final  int I = i;
            new Thread(()->{
                try {
                    System.out.println("集齐了第" + I + "颗龙珠");
                    cyclicBarrier.await();//等待,直到达到cyclicBarrier设定的界定值。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }

    }
}

在这里插入图片描述

8.3 Semaphore

在这里插入图片描述

package com.seapp.sample;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @author seapp
 * @date 2021/6/15 10:12
 */
public class SemaphoreDemo {

    //以抢车位的案例阐述:
    public static void main(String[] args) {

        //semaphore信号量
        Semaphore semaphore = new Semaphore(2);

        for (int i = 0; i < 6; 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();//释放许可证
                }
            },String.valueOf(i)).start();
        }

    }

}
  • semaphore.acquire():获得,假设已经满了,等待。等待被释放为止。
  • semaphore.release():释放,会将当前的信号释放量+1。然后唤醒等待的线程。

作用:多个共享资源互斥的使用。并发限流,控制最大的线程数。

第九节:读写锁
9.1 ReadWriteLock

在这里插入图片描述

package com.seapp.sample;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author seapp
 * @date 2021/6/15 14:24
 */
public class ReadWriteLockDemo {

    public static void main(String[] args) {

        //通过myCache类进行缓存
//        MyCache myCache = new MyCache();
        MyCacheLock myCache = new MyCacheLock();

        //写入数据
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.put(temp+"",temp + "");
            },String.valueOf(temp)).start();
        }

        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.get(temp+ "");
            },String.valueOf(temp)).start();
        }

    }

}

class MyCacheLock{
    private volatile Map<String,Object> map = new HashMap<>();

    //读写锁,更加细类度的控制
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Lock lock = new ReentrantLock();

    /**
     * 写入数据
     * @param key
     * @param object
     */
    public void put(String key,Object object){
        //写锁
        readWriteLock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + "开始写入数据: " + key);
            map.put(key,object);
            System.out.println(Thread.currentThread().getName() + "写入完成了");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            readWriteLock.writeLock().unlock();
        }
    }

    public void get(String key){
        readWriteLock.readLock().lock();//读锁
        try {
            System.out.println(Thread.currentThread().getName() + "开始读取数据:" + key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取数据完成并返回:" + o.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            readWriteLock.readLock().unlock();
        }
    }
}

/**
 * 自定义缓存
 */
class MyCache{

    private volatile Map<String,Object> map = new HashMap<>();

    public void put(String key,Object object){
        System.out.println(Thread.currentThread().getName() + "开始写入数据:" + key);
        map.put(key,object);
        System.out.println(Thread.currentThread().getName() + "写入数据:OK");
    }

    public void get(String key){
        System.out.println(Thread.currentThread().getName() + "开始读取数据:" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取数据完成:" + o.toString());
    }

}
第十节:阻塞队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

**什么情况下会使用阻塞队列:**多线程并发处理、线程池!

在这里插入图片描述

package com.seapp.queue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @author seapp
 * @date 2021/6/15 15:28
 */
public class BlockingQueueDemo {

    public static void main(String[] args) throws InterruptedException {
//        test1();//抛出异常
//        test2();//不抛出异常,有返回值
//        test3();//一直等待下去
        test4();//等待,等超时后停止等待。并给出返回值。
    }


    /**
     * 抛出异常
     */
    public static void test1(){

        ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);

        //添加add
        blockingQueue.add(1);
        blockingQueue.add(2);
        blockingQueue.add(3);
        //测试添加多余初始设定时,是否会报错(Exception in thread "main" java.lang.IllegalStateException: Queue full)
//        blockingQueue.add(4);
        //移除
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //当队列元素为空时,再执行移除操作会报异常(Exception in thread "main" java.util.NoSuchElementException)
        System.out.println(blockingQueue.remove());


    }

    /**
     * 有返回值,不抛出异常
     */
    private static void test2() {
        ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);

        //添加元素
        System.out.println(blockingQueue.offer(1));
        System.out.println(blockingQueue.offer(2));
        System.out.println(blockingQueue.offer(3));
        //当使用blockingQueue.offer添加元素多于初始设定大小时,不会抛出异常。执行结果返回false
        System.out.println(blockingQueue.offer(4));

        //获取元素
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        //当使用blockingQueue.poll获取元素多于存入值时,不会抛出异常。执行结果为null
        System.out.println(blockingQueue.poll());


    }


    public static void test3() throws InterruptedException {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);

        blockingQueue.put(1);
        blockingQueue.put(2);
        blockingQueue.put(3);
        //当给队列中添加的元素多余初始设定值时,会一直等待...
//        blockingQueue.put(4);

        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        //当给队列中获取的元素多余初始设定值时,会一直等待...
        System.out.println(blockingQueue.take());
    }

    public static void test4() throws InterruptedException {

        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.offer(1));
        System.out.println(blockingQueue.offer(2));
        System.out.println(blockingQueue.offer(3));
        //当使用blockingQueue.offer添加队列数量超过初始设定值时,会等待设定的时长。等超时后,退出等待。
        System.out.println(blockingQueue.offer(4, 2, TimeUnit.SECONDS));

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));//超出时,等待。超时后,返回处理结果null
    }

}
第十一节:线程池

**线程池:**三大方法、七大参数、四种拒绝策略。

  • 池化技术:程序的运行,本质是占用系统的资源!优化资源的使用====》池化技术。
  • 池化技术事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。

线程池的好处:

  • 降低资源的消耗
  • 提高响应的速度
  • 方便管理。

线程复用,可以控制最大并发数、管理线程。

11.1 线程池的三大方法:

在这里插入图片描述

ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
ExecutorService threadPool = Executors.newFixedThreadPool(5);//指定数目的线程池
ExecutorService threadPool = Executors.newCachedThreadPool();//可伸缩的,依照需求量来定
 	/**
     * @param corePoolSize  //核心线程池大小
     * @param maximumPoolSize //最大核心线程池大小
     * @param keepAliveTime   //超时了没被调用,就会被释放
     * @param unit          //超时单位
     * @param workQueue     //阻塞队列
     * @param threadFactory //线程工厂,创建线程的。一般不用动
     * @param handler      //拒绝策略
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

    }

银行实例

在这里插入图片描述

  //线程池本质上是ThreadPoolExecutor,自定义线程池
        /**
         //     * @param corePoolSize  //核心线程池大小
         //     * @param maximumPoolSize //最大核心线程池大小
         //     * @param keepAliveTime   //超时了没被调用,就会被释放
         //     * @param unit          //超时单位
         //     * @param workQueue     //阻塞队列
         //     * @param threadFactory //线程工厂,创建线程的。一般不用动
         //     * @param handler      //拒绝策略
         //     */
        ExecutorService threadPool = new ThreadPoolExecutor(5,10,3,TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(),Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
11.2 四种拒绝策略

在这里插入图片描述

在这里插入图片描述

11.3 池的最大和最小如何去设置?

了解:IO密集型和CPU密集型(调优)

第十二节:lambda表达式,链式编程,函数式编程、Stream流式计算

lambda表达式,链式编程,函数式编程、Stream流式计算

12.1 四大函数式接口:只有一个方法的接口

在这里插入图片描述

  • Function函数式编程

在这里插入图片描述

package com.seapp.function;

import java.util.function.Function;

/**
 * @author seapp
 * @date 2021/6/16 9:20
 *  function函数式接口,有一个输入参数,有一个返回参数
 *  只要是函数式接口,就可以用lambda表达式简化
 */
public class FunctionDemo {

    public static void main(String[] args) {
//        Function<String, Integer> stringIntegerFunction = new Function<String,Integer>() {
//
//            @Override
//            public Integer apply(String s) {
//                return Integer.valueOf(s);
//            }
//        };
//
//        Integer apply = stringIntegerFunction.apply("5");
//        System.out.println("apply = " + apply);

        //lambda表达式实现
        Function<String,Integer> function = (str)->{return Integer.valueOf(str);};
        System.out.println(function.apply("5"));
    }

}
  • 断定型接口:有一个输入型参数,返回值只能是布尔值。

在这里插入图片描述

package com.seapp.function;

import com.sun.deploy.util.StringUtils;

import java.util.function.Predicate;

/**
 * @author seapp
 * @date 2021/6/16 9:34
 * 断定型接口:有一个输入值,输出只能是布尔值
 *
 */
public class PredicateDemo {

    public static void main(String[] args) {
       /* Predicate<String> stringPredicate = new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.isEmpty();
            }
        };

        System.out.println(stringPredicate.test("test"));*/

        //lambda表达式测试
        Predicate<String> predicate = (str)->{
            return str.isEmpty();
        };
        System.out.println(predicate.test(""));
    }

}
  • Consumer:消费型接口。只有输入,没有返回值

在这里插入图片描述

package com.seapp.function;

import java.util.function.Consumer;

/**
 * @author seapp
 * @date 2021/6/16 9:53
 * 消费型接口:只有输入没有输出
 */
public class ConsumerDemo {

    public static void main(String[] args) {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("s = " + s);
            }
        };

        consumer.accept("consumer");

        //lambda表达式测试:
        Consumer<String> lambda = (str)->{
            System.out.println("str = " + str);
        };
        lambda.accept("lambdaConsumer");
    }
}
  • Supplier 供给型接口

在这里插入图片描述

package com.seapp.function;

import java.util.function.Supplier;

/**
 * @author seapp
 * @date 2021/6/16 10:00
 * 供给型接口:没有输入,只有返回值
 */
public class SupplierDemo {

    public static void main(String[] args) {
        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                System.out.println("get方法被调用了");
                return 1024;
            }
        };
        System.out.println(supplier.get());

        //lambda表示式的调用
        Supplier<Integer> lambdaSupplier = ()->{
            System.out.println("get方法被调用了");
            return 2048;
        };
        System.out.println(lambdaSupplier.get());

    }

}
12.2 Stream流式计算

大数据:存储+计算

集合、Mysql本质上就是存储数据

计算都应该交给流来操作。

在这里插入图片描述
实例验证:

package com.seapp.stream;

import java.util.Arrays;
import java.util.List;

/**
 * 流式计算验证
 * @author seapp
 * @date 2021/6/16 10:18
 */
public class StreamDemo {

    /**
     * 题目:现有5个用户,筛选
     * 1、ID必须是偶数
     * 2、年龄必须大于23岁
     * 3、用户名转为大写字母
     * 4、用户字母倒着排序
     * 5、只输出一个用户
     * @param args
     */
    public static void main(String[] args) {

        User u1 = new User(1,"a",21);
        User u2 = new User(2,"b",22);
        User u3 = new User(3,"c",23);
        User u4 = new User(4,"d",24);
        User u5 = new User(5,"e",25);

        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);

        list.stream().filter(user ->{return user.getId()%2 ==0;})
//                .filter(user -> {return user.getAge() > 23;}) //lambda表达式中return的省略,方式如下:
                .filter(user -> user.getAge() > 23)
                .map(user ->{return user.getName().toUpperCase();})
                .limit(1)
                .forEach(System.out::println);


    }

}
第十三节:ForkJoin

什么是ForkJoin: 在JDK1.7中,并行执行任务!提高效率。大数据量!

大数据: Map Reduce(把大任务拆分成小任务)

在这里插入图片描述

ForkJoin特点:工作窃取 (任务队列使用的是双端队列)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.seapp.forkjoin;

import java.util.concurrent.RecursiveTask;

/**
 *
 * @author seapp
 * @date 2021/6/16 10:45
 * forkJoin的使用
 * 1.通过forkJoinPool来执行
 * 2.计算任务:forkJoinPool.execute(ForkJoinTask task)
 * 3.计算类要继承 ForkJoinTask;
 *
 */
public class ForkJoinDemo extends RecursiveTask<Long> {

    private Long start;//起始值
    private Long end;//结束值

    private Long temp = 10000L;//临界值

    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, end);
            task2.fork();//将拆分的任务队列压入栈中
            //获取任务执行的结果
            return task1.join() + task2.join();
        }
    }
}
package com.seapp.forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

/**
 * @author seapp
 * @date 2021/6/16 10:56
 * forkJoin测试类
 */
public class ForkJoinTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        test1();//简单的加法运算 sum = 499999999500000000  耗时时间:5003
//        test2();//通过forkJoin进行计算aLong = 499999999500000000 耗时时长:8838
        test3();//通过流式计算来计算和:sum = 499999999500000000  耗时时间:509

    }




    private static void test1() {

        Long sum = 0L;
        long start = System.currentTimeMillis();
        for (long i = 1L; i < 1000_000_000L; i++) {
            sum += i;
        }
        long end = System.currentTimeMillis();

        System.out.println("sum = " + sum);
        System.out.println("耗时时间:" + (end - start));

    }

    private static void test2() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ForkJoinDemo task = new ForkJoinDemo(0L, 1000_000_000L);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);
        Long aLong = submit.get();
        long end = System.currentTimeMillis();
        System.out.println("aLong = " + aLong);
        System.out.println("耗时时长:"+(end-start));
    }


    private static void test3() {
        long start = System.currentTimeMillis();
        long sum = LongStream.range(0L,1000_000_000L).parallel().reduce(0,Long::sum);
        System.out.println("sum = " + sum);
        long end = System.currentTimeMillis();
        System.out.println("耗时时间:" + (end - start));
    }
}
第十四节:异步回调

Future: 设计的初衷,对将来的某个事件的结果进行建模。

在这里插入图片描述

package com.seapp.future;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 异步调用测试
 * @author seapp
 * @date 2021/6/16 14:44
 */
public class FutureDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

      /*  //异步执行无返回值得调用
        CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "  runAsync--->Void");
        });

        System.out.println(Thread.currentThread().getName() + " main ");//主线程先调用。

        //执行异步回调
        future.get();
*/

        //有返回值得回调。supplyAsync
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName() + "supplyAsync--->Integer" );
            int i = 10/0;
            return 1024;
        });

        //获取结果
        completableFuture.whenComplete((t,u)->{
            System.out.println("t = " + t); //成功的返回结果
            System.out.println("u = " + u); //异常信息
        }).exceptionally((e)->{
            System.out.println(e.getMessage()); //异常信息
            return 400;
        });


    }

}

执行结果:

在这里插入图片描述

第十五节:JMM
15.1 谈谈对Volatile的理解:

Volatile是Java虚拟机提供轻量级的同步机制,有三个重要特性:

  • 保障可见性
  • 不保障原子性
  • 禁止指令重排
15.2 什么是JMM:

JMM: Java内存模型,不存在的东西。概念!约定!

  • 线程解锁前,必须把共享变量立刻刷回主内存。
  • 线程加锁前,必须读取主内存中的最新值到工作内存中。
  • 加锁和解锁是同一把锁。

JMM的8中操作:
在这里插入图片描述
在这里插入图片描述

内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类
型的变量来说,load、store、read和write操作在某些平台上允许例外)

  • lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态
  • unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量
    才可以被其他线程锁定
  • read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便
    随后的load动作使用
  • load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中
  • use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机
    遇到一个需要使用到变量的值,就会使用到这个指令
  • assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变
    量副本中
  • store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,
    以便后续的write使用
  • write (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内
    存的变量中
    JMM对这八种指令的使用,制定了如下规则:
  • 不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须
    write
  • 不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
  • 不允许一个线程将没有assign的数据从工作内存同步回主内存
  • 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量
    实施use、store操作之前,必须经过assign和load操作
  • 一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解
  • 如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,
    必须重新load或assign操作初始化变量的值
  • 如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
    对一个变量进行unlock操作之前,必须把此变量同步回主内存

在这里插入图片描述

存在的东西。概念!约定!**

  • 线程解锁前,必须把共享变量立刻刷回主内存。
  • 线程加锁前,必须读取主内存中的最新值到工作内存中。
  • 加锁和解锁是同一把锁。

JMM的8中操作:

[外链图片转存中…(img-PFpk4Opk-1634117381689)]

[外链图片转存中…(img-RkIZG3Pw-1634117381690)]

内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类
型的变量来说,load、store、read和write操作在某些平台上允许例外)

  • lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态
  • unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量
    才可以被其他线程锁定
  • read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便
    随后的load动作使用
  • load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中
  • use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机
    遇到一个需要使用到变量的值,就会使用到这个指令
  • assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变
    量副本中
  • store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,
    以便后续的write使用
  • write (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内
    存的变量中
    JMM对这八种指令的使用,制定了如下规则:
  • 不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须
    write
  • 不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
  • 不允许一个线程将没有assign的数据从工作内存同步回主内存
  • 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量
    实施use、store操作之前,必须经过assign和load操作
  • 一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解
  • 如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,
    必须重新load或assign操作初始化变量的值
  • 如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
    对一个变量进行unlock操作之前,必须把此变量同步回主内存

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值