JUC并发编程-1

JUC并发编程

进程和线程

进程:

  • 一个进程可以包含多个线程。

  • 进程是资源分配的最小单位。

线程:

  • 线程是资源调度的最小单位。
  • java实际上无法开启线程

Runnable没有返回值,效率相比Callable相对较低!

查询cpu核数

    public static void main(String[] args) {
        //获取cpu的核数
        //cpu密集型 IO密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
    }

并发编程:并发、并行

并行:两个或多个事件在同一个时刻发生。

并发:多个进程指令被快速的轮换执行,同一时刻只有一条指令执行。

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

wait和sleep的区别:

  1. 来自不同的类
    wait–>Object
    sleep–>Thread

  2. 关于锁的释放
    wait会释放锁
    sleep不会释放锁,会抱着锁睡觉,不释放

  3. 适用范围不同
    wait必须在同步代码块中
    sleep可以在任何地方睡

  4. 是否捕获异常
    wait不需要捕获异常
    sleep必须捕获异常

传统Synchronize锁

public class SaleTicketDemo01 {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "B").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }
        },"C").start();
    }
    //资源类
    static class Ticket {
        //属性 方法
        private int number = 50;
        //卖票的方式
        public void sale() {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出去" + (number--) + "张票,剩余:" + number);
            }
        }
    }
}

LOCK锁

公平锁:非常公平,不可以插队。

非公平锁:不公平,可以插队。(默认)

lock锁

package com.kang.demo01;

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

public class SaleTicketDemo02 {

    public static void main(String[] args) {

        SaleTicketDemo01.Ticket ticket = new SaleTicketDemo01.Ticket();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }

        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "B").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }
        }, "C").start();
    }


    //Lock三部
    //1.创建锁 Lock lock = new ReentrantLock();
    //2.加锁 lock.lock();
    //3.释放锁 lock.unlock();
    //资源类
    static class Ticket {
        //属性 方法
        private int number = 50;
        Lock lock = new ReentrantLock();

        //卖票的方式
        public synchronized void sale() {
            //加锁
            lock.lock();
            try {
               //业务代码
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName() + "卖出去第" + (number--) + "张票,剩余:" + number);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }
    }
}

Synchronize锁和Lock锁区别

  1. Synchronize 内置的Java关键字 Lock是一个java类
  2. Synchronize 无法判断获取锁的状态 Lock可以判断是否获取到了锁
  3. Synchronize会自动释放锁 Lock必须要手动释放锁,如果不释放会死锁
  4. Synchronize 线程1(获得锁,阻塞) 线程2(持续等待) Lock锁不一定持续等待
  5. Synchronize 可重入锁,不可以中断,非公平 Lock 可重入锁,可以 判断锁,非公平(可以自己设置)
  6. Synchronize 适合锁少量的代码同步问题 Lock锁可以锁大量的代码

广义上的可重入锁指的是可重复调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁

锁是什么,如何判断锁!	

消费者与生产者问题 Synchronize版本


/*
生产者消费者问题
等待唤醒 通知唤醒
线程交替执行 A B操作同一个变量 num = 0
A num+1
B num-1
 */

import java.util.Date;

public class A {

    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {

            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
    }
}

//等待 业务 通知
class Data { //数字资源类

    private int number = 0;
    //+1
    public synchronized void increment() throws InterruptedException {
        while (number != 0) {
            //等待
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "-->" + number);
        //通知其他线程,我+1完毕了
        this.notifyAll();
    }
    
    //-1
    public synchronized void decrement() throws InterruptedException {
      	//if 可能会产生虚假唤醒的问题
        while (number == 0) {
            //等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "-->" + number);
        //通知其他线程,我-1完毕了
        this.notifyAll();
    }
}

if 解决阻塞状态时,会执行接下来的代码;而使用while,在解除阻塞时,需要直到满足条件才会执行接下来的代码 if判断只判断一次 ,while是满足条件时才执行

采用if判断,唤醒后会从wait之后的代码开始运行,运行过程中不再进行判断。使用while的话,唤醒之后也是从wait之后的代码开始运行,但是唤醒后会重新判断循环条件,如果需要等待则继续等待,不需要等待则执行后续代码。

消费者与生产者问题 Lock版本


public class B {

    public static void main(String[] args) {

        Data data = new Data();

        new Thread(() -> {

            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

    }
}


//等待 业务 通知
class Data2 { //数字资源类

    private int number = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    //    condition.await(); //等待
    //    condition.signalAll(); //唤醒全部


    //+1
    public void increment() throws InterruptedException {

        lock.lock();
        try {
            if (number != 0) {
                //等待
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "-->" + number);
            //通知其他线程,我+1完毕了
            this.notifyAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    //-1
    public void decrement() throws InterruptedException {
        lock.lock();
        try {
            if (number == 0) {
                //等待
                condition.signalAll();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "-->" + number);
            //通知其他线程,我-1完毕了
            this.notifyAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Condition 精准的通知和唤醒线程

//A执行完调用B,B执行完哇调用C,C执行完调用A
public class C {

    public static void main(String[] args) {

        Data3 data3 = new Data3();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printA();
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printB();
            }
        }, "B").start();


        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data3.printC();
            }
        }, "C").start();

    }


    static class Data3 { //资源类 lock
        private Lock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();

        //1A 2B 3C
        private int number = 1;
//        private int number =2;
//        private int number =3;


        public void printA() {
            lock.lock();
            try {
                //业务 判断-> 执行-> 通知
                while (number != 1) {
                    condition1.await();
                }
                System.out.println(Thread.currentThread().getName() + "-->AAAA");
                // 唤醒 唤醒指定的人 B
                number = 2;
                condition2.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void printB() {
            lock.lock();
            try {
                while (number != 2) {
                    condition2.await();
                }
                System.out.println(Thread.currentThread().getName() + "-->BBBB");
                number = 3;
                condition3.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void printC() {
            lock.lock();
            try {
                while (number != 3) {
                    condition3.await();
                }
                System.out.println(Thread.currentThread().getName() + "--->CCCC");
                number = 1;
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

}

8锁现象

  1. 电话短信问题
//关于锁的8个问题
public class Test1 {

    public static void main(String[] args) {

        Phone phone = new Phone();
       new Thread(()->{
           phone.sendMessage();
       },"A").start();

       //捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        new Thread(()->{
           phone.call();
       },"B").start();
    }

}

class Phone {
    //synchronized 锁的对象是方法的调用者
    //两个方法用的同一个锁,谁先拿到谁先执行
    public synchronized void sendMessage() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送信息");
    }

    public synchronized void call() {
        System.out.println("打电话");
    }
}

发送信息
打电话
  1. 信息与hello问题
package com.kang.lock8;

import java.util.concurrent.TimeUnit;

public class Test2 {


        public static void main(String[] args) {

            Phone2 phone2 = new Phone2();
            new Thread(()->{
                phone2.sendMessage();
            },"A").start();

            //捕获
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            new Thread(()->{
                phone2.hello();
            },"B").start();
        }

    }

    class Phone2 {
        //synchronized 锁的对象是方法的调用者
        //两个方法用的同一个锁,谁先拿到谁先执行
        public synchronized void sendMessage() {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("发送信息");
        }

        public synchronized void call() {
            System.out.println("打电话");
        }
        //这里没有锁,不是同步方法,不受锁的影响
        public  void hello() {
            System.out.println("hello");
        }
    }

hello
发送信息
  1. 两个对象的调用顺序
public class Test3 {

    //增加两个静态的同步方法  只有一个对象
    public static void main(String[] args) {

//      //两个对象的Class类模板只有一个 static  锁的是class
//        Phone3 phone1 = new Phone3();
//        Phone3 phone2 = new Phone3();


        //两个对象  两把锁 两个调用者 按照时间先后顺序来
        Phone3 phone3 = new Phone3();
        //锁的存在
        new Thread(() -> {
            phone3.sendMessage();
        }, "A").start();

        //捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            phone3.call();
        }, "B").start();
    }

}

//Phone3 全局唯一的一个class对象
class Phone3 {
    //synchronized 锁的对象是方法的调用者
    //static 静态方法
    //类一加载就有了 class 模板
    public static synchronized void sendMessage() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送信息");
    }

    public static synchronized void call() {
        System.out.println("打电话");
    }

    //这里没有锁,不是同步方法,不受锁的影响
    public void hello() {
        System.out.println("hello");
    }
}


发送信息
打电话
  1. 静态方法与普通同步方法
package com.kang.lock8;

import java.util.concurrent.TimeUnit;

public class Test4 {

    public static void main(String[] args) {

        //一个静态方法 一个普通的同步方法 一个对象
        //一个静态方法 一个普通的同步方法 两个对象  静态方法锁的是class模板 下边的

        //两个对象的Class类模板只有一个 static  锁的是class
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        //锁的存在
        new Thread(() -> {
            phone2.sendMessage();
        }, "A").start();

        //捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            phone1.call();
        }, "B").start();
    }
}


//Phone4 全局唯一的一个class对象
class Phone4 {

    //静态同步方法 锁的是Class类模板
    public static synchronized void sendMessage() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送信息");
    }

    //普通同步方法
    public synchronized void call() {
        System.out.println("打电话");
    }

    //这里没有锁,不是同步方法,不受锁的影响
    public void hello() {
        System.out.println("hello");
    }

}

打电话
发送信息

  • 静态同步锁和非静态同步方法之间不会有竞争条件,这两把锁是两个不同的对象,非静态同步方法是锁对象,静态同步锁是锁Class模板类。

  • 一个静态同步方法获得锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁。

new this 具体的一个手机 实体

static 锁class 是唯一的

如果是同一个锁看谁先得到,如果不是同一个锁,就看是否休眠。

集合类不安全

List不安全

CopyOnWriteArrayList

public class ListTest {

    public static void main(String[] args) {

//        List<String> list = Arrays.asList("1", "2", "3");
//        list.forEach(System.out::println);
        /*
        并发下ArrayList不安全
        解决方案
        1.List<Integer> list = new Vector<>();
        2.List<Object> list = Collections.synchronizedList(new ArrayList<>());
        3.List<Object> list = new CopyOnWriteArrayList<>();
         */

        //CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略
        //多个线程调用的时候,list,读取的时候,固定的 写入(覆盖)
        //在写入的时候避免覆盖,造成数据问题
        //读写分离
        // synchronized 效率比较低
        
        List<Object> list = new CopyOnWriteArrayList<>();

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

CopyOnWriteArraySet

//java.util.ConcurrentModificationException  并发修改异常
public class SetTest {

    /*
    Set<Integer> set = new HashSet<>(); 不安全

    解决方案:
    1.Set<Integer> set = Collections.synchronizedSet(new HashSet<>());
    2.Set<Integer> set = new CopyOnWriteArraySet<>();
     */

    public static void main(String[] args) {
        Set<Object> set = new HashSet<>();
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            }, String.valueOf(i)).start();

        }
    }
}

HashSet底层是什么

   public HashSet() {
        map = new HashMap<>();
    }
    //add set 本质就是 map key是无法重复的
  public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
private static final Object PRESENT = new Object();//不变的值

ConcurrentHashMap

Map不安全
// java.util.ConcurrentModificationException
public class MapTest {

    public static void main(String[] args) {
        //工作中不用HashMap  Map<Integer, String> map = new HashMap<>(); 不安全
        //默认等价于什么  new HashMap<>() 等价于 new HashMap<>(16, 0.75f)
        Map<Object, Object> map = new ConcurrentHashMap<>();

        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
                System.out.println(map);
            }).start();
        }
        //加载因子 初始化容量
        //散列表填满的程度
    }
}

Callable

  1. 可以有返回值
  2. 可以抛出异常
  3. 方法不同 call()

public class CallableTest {

    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();

        new Thread().start(); //怎么启动callable
        MyThread thread = new MyThread();
        FutureTask futureTask = new FutureTask(thread);//适配类
        new Thread(futureTask, "A").start();
        new Thread(futureTask, "B").start();

        Integer o = (Integer) futureTask.get(); //这个get 方法可能会产生阻塞!把它放到最后
        //使用异步通信来处理
        System.out.println(o);
    }
}

class MyThread implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("call()");
        return 1024;
    }
}
  1. 有缓存
  2. 结果可能需要等待 会阻塞

常用辅助类

CountDownLatch (减法计数器)

public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        //总数是6  必须要执行任务时再使用
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "Go out");
                countDownLatch.countDown();//数量-1 ***
            }, String.valueOf(i)).start();
        }
        countDownLatch.await(); //等待计数器归零,然后再向下执行 ***
        System.out.println("Close the Door");
    }
}

原理:

 countDownLatch.countDown();//数量-1 
 countDownLatch.await(); //等待计数器归零,然后再向下执行

每次有线程用countDown()数量-1,假设计数器变0,countDownLatch.await()就会被唤醒,继续执行

CyclicBarrier (加法计数器)

public class CyclicBarrierDemo {
    
    public static void main(String[] args) {
        /*
        加法计算器
         */
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("召唤神龙!!!");
        });
        
        for (int i = 1; i <= 7; i++) {
            final int temp = i;
            //lambda 能操作到i吗
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "收集" + temp + "个龙珠");
                try {
                    cyclicBarrier.await();//等待计算器变为7
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Semaphore

semaphore 信号量

public class SemaphoreDemo {

    public static void main(String[] args) {
        //线程数量:停车位 限流
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                //acquire() 得到
                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 {
                    //release() 释放
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

原理:

semaphore.acquire(); 得到 假设如果已经满了 等待 等待被释放为止
semaphore.release();  释放 会将当前的信号量释放+1 然后唤醒等待的线程

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

读写锁


/*
ReadWriteLock
独占锁(写锁) 一次只能被一个线程占有
共享锁(读锁) 多个线程可以同时占有
读-读 可以共存
读-写 不能共存
写-写 不能共存
 */
public class ReadWriteLockDemo {


    public static void main(String[] args) {

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

//加锁的
class MyCacheLock {

    private volatile Map<String, Object> map = new HashMap<>();
    //读写锁  更加细粒度的控制
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();


    //存,写  只希望同时只有一个线程写
    public void put(String key, Object value) {

        readWriteLock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完毕" + key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            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() + "读取完毕" + key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }



    }
}


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

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

    //存,写
    public void put(String key, Object value) {
        System.out.println(Thread.currentThread().getName() + "写入" + key);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName() + "写入完毕" + key);
    }

    //取
    public void get(String key) {
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取完毕" + key);
    }
}

BlockingQueue(阻塞队列 )

阻塞队列:线程池 多线程并发处理

四组API

方式抛出异常有返回值,不抛出异常阻塞等待超时等待
添加add()offer()put()offer( , )
移除remove()poll()take()poll( , )
检测队首元素element()peek()--
  1. 抛出异常
  2. 不会抛出异常
  3. 阻塞等待
  4. 超时等待
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        test3();
    }

    /*
    抛出异常 有返回值
     */
    public static void test1() {
        //队列的大小
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
        //IllegalStateException: Queue full
        //System.out.println(blockingQueue.add("d"));
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //NoSuchElementException
        // System.out.println(blockingQueue.remove());

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

        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        //  System.out.println(blockingQueue.offer("d"));//false  不能抛出异常
       
        System.out.println(blockingQueue.element());//检查队首是哪个
        System.out.println(blockingQueue.peek());

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll()); //null 不抛出异常

    }

    /*
    阻塞等待 一直等
     */
    public  static  void  test3() throws InterruptedException {

        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        blockingQueue.put("d");

        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 blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.offer("a");
        blockingQueue.offer("b");
        blockingQueue.offer("c");
        blockingQueue.offer("d",2, TimeUnit.SECONDS);

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        blockingQueue.poll(2,TimeUnit.SECONDS);
    }

}

线程池(重点)

池化技术

程序的运行会占用系统的资源,池化技术有助于优化资源的使用

线程池、连接池、内存池、对象池

池化技术:事先贮备一些资源,需要用时来拿,用完还回来

线程池的优点:

  1. 降低资源的消耗
  2. 提高响应的速度
  3. 方便管理

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

线程池 三大方法、七大参数、4种拒绝策略

三种方法

public class Demo01 {
    public static void main(String[] args) {
		//三种创建方法
        ExecutorService threadPool1 = Executors.newSingleThreadExecutor();//单个线程
        ExecutorService service = Executors.newFixedThreadPool(5);//创建固定大小的线程池
        ExecutorService service1 = Executors.newCachedThreadPool();//可伸缩的

        try {
            for (int i = 0; i < 10; i++) {
                service.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完 程序结束 关闭线程池
            service.shutdown();
        }
    }
    
}

七种参数

    public ThreadPoolExecutor(int corePoolSize,  //核心线程池大小
                              int maximumPoolSize, //最大核心线程池大小
                              long keepAliveTime,// 存活时间 超时了没有人调用就会释放
                              TimeUnit unit, //超时单位
                              BlockingQueue<Runnable> workQueue, //阻塞队列
                              ThreadFactory threadFactory, //线程工厂 创建线程的
                              RejectedExecutionHandler handler) //拒绝策略{ 
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

四种拒绝策略

1	
	银行满了,还有人进来,不处理这个人
	队列满了,线程数达到最大线程数,还有线程过来,不处理这个线程。抛出异常
	new ThreadPoolExecutor.AbortPolicy();
2	
	哪里来的到哪儿去,由调用线程处理该任务。谁调用,谁处理
	new ThreadPoolExecutor.CallerRunsPolicy()
3
	队列满了,丢掉任务。不会抛出异常
    new ThreadPoolExecutor.DiscardPolicy()
4
	队列满了,任务拒绝被添加时 将最早进入队列的任务删除 之后再尝试加入队列   不会抛出异常
	new ThreadPoolExecutor.DiscardOldestPolicy());

如何定义最大线程

  1. CPU密集型 几核就是几,可以保证CPU效率最高
  2. I/O密集型 判断程序中十分耗I/O的线程 假如有15个十分消耗I/O的大型任务 一般设置为2倍 30

四大函数型接口

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

	   @FunctionalInterface
		public interface Runnable {
            public abstract void run();
        }
	//很多函数式接口
	//简化编程模型,在新版本的框架底层大量应用
	//foreach(消费者类型的函数式接口)

Function

函数式接口
public class Demo01 {
    public static void main(String[] args) {
        //工具类 输出输入的值 输入什么 输出什么
        //匿名内部类
        //1.
        Function function = new Function<String, String>() {
            @Override
            public String apply(String o) {
                return o;
            }
        };
        //2.
        Function function1 = (s) -> {
            return s;
        };
        System.out.println(function1.apply("asd"));
    }
}

Predicate

断定型接口:有一个输入参数,返回只能是布尔值
    
    /*
    断定型接口:有一个输入参数,返回值只能是布尔值
     */
    public class Demo02 {
        public static void main(String[] args) {
            //1.
            Predicate predicate = new Predicate<String>() {
                @Override
                public boolean test(String str) {
                    return str.isEmpty();
                }
            };
            //2.
            Predicate<String> predicate1 = (str) -> {
                return str.isEmpty();
            };
            //判断是否为空
            System.out.println(predicate1.test("asd"));
        }
    }

Consumer

Consumer 消费型接口:只有输入,没有返回值
/*
消费型接口 Consumer  只有输入 没有返回值
 */
public class Demo03 {
    public static void main(String[] args) {
        //1.
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String str) {
                System.out.println(str);
            }
        };
        //2.
        Consumer<String> consumer1 =(str)->{
            System.out.println(str);
        };
        consumer1.accept("asd");
    }

Supplier

Supplier 供给型接口
public class Demo04 {
    public static void main(String[] args) {

        //没有参数 只有返回值
        //1.
        Supplier supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                System.out.println("get()");
                return 1024;
            }
        };
        //2.
        Supplier supplier1 = () -> {
            return 1024;
        };
        System.out.println(supplier1.get());
    }
}

Stream流式计算

什么是流式计算

大数据 :存储 + 计算

集合、MySQL本质就是存储东西的:

计算应该交给流去做

/*
 * 题目要求:一分钟内完成此题,只能用一行代码实现
 * 现在有5个用户!筛选
 * 1.ID必须是偶数
 * 2.年龄必须大于23岁
 * 3.用户转为大写
 * 4.用户名字母倒着排序
 * 5.只输出一个用户
 */
public class Test {

    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(6, "e", 25);

        //集合就是存储
        List<User> users = Arrays.asList(u1, u2, u3, u4, u5);

        users.stream().filter(u -> {
            return u.getId() % 2 == 0;
        }).filter(u -> {
            return u.getAge() > 23;
        }).map(u -> {
            return u.getName().toUpperCase();
        }).sorted((uu1, uu2) -> {
            return uu2.compareTo(uu1);
        }).limit(1).forEach(System.out::println);
    }

   static class User {

        private int id;
        private String name;
        private int age;

        public User() {
        }

        public User(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "User1{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

    }

}

Forkjoin


/*
求和计算的任务
Forkjoin  Stream并行流
 */
public class ForkJoin extends RecursiveTask<Long> {
    private Long start;
    private Long end;
    //临界值
    private Long temp = 10000L;
    public static void main(String[] args) {
        int sum = 0;
        for (int i = 0; i < 1_0000_0000; i++) {
            sum += i;
        }
        System.out.println(sum);
    }
    public ForkJoin(Long start, Long end) {
        this.start = start;
        this.end = end;
    }
    //计算方法
    public 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; //中间值
            ForkJoin task1 = new ForkJoin(start, middle);
            task1.fork();
            ForkJoin task2 = new ForkJoin(middle + 1, end);
            task2.fork();
            return task1.join()+task2.join();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值