JUC学习

1、什么是JUC

源码+官方文档 面试高频问

在这里插入图片描述

java.util工具包、包、分类

业务:普通的线程代码 Thread

Runnable 没有返回值、效率相比Callable低

在这里插入图片描述

在这里插入图片描述

2、线程和进程

线程、进程,如果不能使用一句话说出来的技术,不扎实!

进程:一个程序,QQ.exe Music.exe程序的集合:

一个进程往往可以包含多个线程,至少包含一个!

java默认有两个线程?:一个main线程,一个gc线程

线程:开了一个进程Typora,写字,自动保存(线程负责的)

对于java而言:Thread,Runnable,Callable

java真的可以开启线程么? 不可以,看下面,最终调用的start方法

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

并发,并行

并发编程:并发,并行

并发(多线程操作同一个资源)

CPU一核,模拟出来多条线程,天下武功,唯快不破,快速交替

并行(多个人一起行走)

CPU多核,多个线程可以同时执行;用线程池提高性能

package com.example.juc;

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

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

所有的公司都很看重!

线程有几个状态?
    public enum State {
        /**
         * 新生
         */
        NEW,
        /**
         * 运行
         */
        RUNNABLE,
        /**
         * 阻塞
         */
        BLOCKED,
        /**
         * 
         * 等待,死死的等
         */
        WAITING,
        /**
         * 超时等待
         */
        TIMED_WAITING,

        /**
         * 终止
         */
        TERMINATED;
    }
wait/sleep的区别
1、来自不同的类

wait=>Object

Sleep=>Thread

2、关于锁的释放

wait会释放锁,sleep睡觉了,抱着锁睡觉,不会释放

3、使用的范围是不同的

wait 必须在同步代码块中

sleep 可以再任何地方谁

//一般采用这种睡
try {
            TimeUnit.DAYS.sleep(1);
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
4、是否需要捕获异常

wait不需要捕获异常

sleep必须要捕获异常

3、lock锁(重点)

传统的Synchronized

lock

在这里插入图片描述

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

公平锁:十分公平,可以先来后到

非公平锁:十分不公平,可以插入(默认)

package com.example.juc;
//基本的买票例子


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

/**
 * 真正的多线程开发,公司中的开发
 * 线程就是一个单独的资源类,没有任何附属的操作!
 * 1、属性,方法
 */
public class SaleTicketDemo02 {
    public static void main(String[] args) {
        //并发:多线程操作同一个资源类,把资源类丢入线程
        Ticket1 ticket = new Ticket1();
        //@FunctionalInterface 函数式接口 jdk1.8 lambda表达式(参数)->{代码}
        new Thread(() -> {
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 60; i++) {
                ticket.sale();
            }
        }, "C").start();
    }
}

class Ticket1 {
    private int number = 50;
    Lock lock = new ReentrantLock();
    public  void sale() {
        lock.lock();
        try {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出了1票 剩余:" + number--);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

Synchronized和lock的区别

1、Synchronized 内置的java关键字,Lock是一个java类

2、Synchronized无法获取锁的状态,Lock可以判断是否获取到了锁

3、Synchronized会自动释放锁,lock必须要手动释放锁!如果不释放,死锁

4、Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等),lock锁就不一定会等待下去

5、Synchronized 可重入锁,不可以中断的,非公平;lock,可重入锁,非公平(可以自己设置)

6、Synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码

锁什么,如何判断锁的是谁!

4、生产者和消费者问题

package com.example.juc;

public class A {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }

}

class Data {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        if (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notify();
    }

    public synchronized void decrement() throws InterruptedException {
        if (number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notify();
    }
}

面试的:单例模式,排序算法,生产者和消费者,死锁

问题存在,A B C D 4个线程!安全不,怎么去解决这个问题

if 改为while

      • 线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒 。 虽然这在实践中很少会发生,但应用程序必须通过测试应该使线程被唤醒的条件来防范,并且如果条件不满足则继续等待。 换句话说,等待应该总是出现在循环中,就像这样:

          synchronized (obj) {
                 while (<condition does not hold>)
                     obj.wait(timeout);
                 ... // Perform action appropriate to condition
             }
        
package com.example.juc;

public class A {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }


}

class Data {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        while (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notify();
    }

    public synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notify();
    }
}

JUC版本的生产者和消费者问题

通过Lock找到condition,condition有signal和 await方法

package com.example.juc;

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

public class B {
    public static void main(String[] args) {
        Data1 data = new Data1();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();
    }


}

class Data1 {
    private int number = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    //condition.await(); 等待
    //condition.signalAll(); 唤醒全部
    public void increment() throws InterruptedException {
        lock.lock();
        try {
            while (number != 0) {
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public  void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (number == 0) {
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

任何一个新的技术不是仅仅只是覆盖原来的技术,会有优势和补充!

如果需要A执行完了通知B,B执行完了通知C,C执行完了通知D,D执行完了通知A

package com.example.juc;

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

public class C {
    public static void main(String[] args) {
        Data2 data = new Data2();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printA();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printB();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printC();
            }
        }, "C").start();
    }
}

class Data2 {
    private int number = 1;
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    public void printA() {
        lock.lock();
        try {
            //业务,判断,->执行 ->通知
            while (number != 1) {
                //等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "->AAAAAAAAAAAAA");
            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() + "->BBBBBBBBBBB");
            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() + "->CCCCCCCCCCC");
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    //生产线:下单-》支付-》交易-》物流
}

5、8锁现象

如果判断锁的是谁!

对象,Class

package com.example.juc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 1、标准情况下,两个线程先打印 发短信还是打电话?
 * 2、sendSms延迟4秒,两个线程先打印 发短信还是打电话?
 */
public class Test1 {
    public static void main(String[] args) {
        Phone1 phone = new Phone1();
        //锁的存在
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}
class Phone1{
    //synchronized 锁的对象是方法的调用者!
    //两个方法用的是同一个锁,谁先拿到,谁执行
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    //这里没有锁,不是同步方法,不受锁的影响
    public void hello(){
        System.out.println("hello");
    }
}
package com.example.juc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 3、增加了一个普通方法后!先执行发短信还是hello?普通方法
 * 4、两个phone对象!先执行发短信还是hello?普通方法
 */
public class Test2 {
    public static void main(String[] args) {
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();
        //锁的存在
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.hello();
        },"B").start();
    }
}

class Phone2{
    //synchronized 锁的对象是方法的调用者!
    //两个方法用的是同一个锁,谁先拿到,谁执行
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    //这里没有锁,不是同步方法,不受锁的影响
    public void hello(){
        System.out.println("hello");
    }
}
package com.example.juc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 5、增加了两个静态的同步方法!先执行发短信还是hello?发短信
 * 6、两个对象!先执行发短信还是hello?发短信
 */
public class Test3 {
    public static void main(String[] args) {
        //两个对象的class类模板只有一个,static,锁的是class
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();
        //锁的存在
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}
//phone3唯一的一个class对象
class Phone3{
    //synchronized 锁的对象是方法的调用者!
    //static 静态方法
    //类一加载就走了!class 模板
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public static synchronized void call(){
        System.out.println("打电话");
    }

}
package com.example.juc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁,就是关于锁的8个问题
 * 7、1个静态的同步方法,一个普通的同步方法,先打印发短信?打电话
 * 8、两个phone对象,先打印发短信?打电话
 */
public class Test4 {
    public static void main(String[] args) {
        //两个对象的class类模板只有一个,static,锁的是class
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        //锁的存在
        new Thread(() -> {
            phone1.sendSms();
        }, "A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            phone2.call();
        }, "B").start();
    }
}


class Phone4 {
    //静态的同步方法
    public static synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

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

}

1、看锁的是对象还是class,加了static的会锁class,没有加sync的不参与锁

6、集合类不安全

list不安全

package com.example.juc.unsafe;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

//Exception in thread "1" java.util.ConcurrentModificationException
public class Test1 {
    public static void main(String[] args) {
        //并发下 Arraylist  不安全的么?
        //List<String> list = new ArrayList<>();
        List<String> list = new CopyOnWriteArrayList<>();
        /*
         *解决方案:
         * 1、List<String> list = new Vector<>();
         * 2、List<String> list = Collections.synchronizedList(new ArrayList<>());
         * 3、List<String> list = new CopyOnWriterArrayList<>();
         */
        //copyOnWrite写入时复制  cow计算机程序设计领域的一种优化策略
        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();
        }
    }
    // public boolean add(E e) {
    //        final ReentrantLock lock = this.lock;
    //        lock.lock();
    //        try {
    //            Object[] elements = getArray();
    //            int len = elements.length;
    //            Object[] newElements = Arrays.copyOf(elements, len + 1);
    //            newElements[len] = e;
    //            setArray(newElements);
    //            return true;
    //        } finally {
    //            lock.unlock();
    //        }
    //    }
}

学习方法:1、先会用 2货比三家,寻找其他解决方案3、分析源码

set不安全

同理,可以new CopyOnWriteArraySet();

HashSet底层是什么?

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

HashMap 不安全

conCurrentHashMap

在这里插入图片描述

7、Callable()

  • @FunctionalInterface
    public interface Callable<V>
    

    返回结果并可能引发异常的任务。实现者定义一个没有参数的单一方法,称为call

    Callable接口类似于Runnable ,因为它们都是为其实例可能由另一个线程执行的类设计的。 然而,A Runnable不返回结果,也不能抛出被检查的异常。

    Executors类包含的实用方法,从其他普通形式转换为Callable类。

package com.example.juc.callable;

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

public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        new Thread(new MyThread()).start();
        MyCallableThread myCallableThread =  new MyCallableThread();
        FutureTask futureTask = new FutureTask<>(myCallableThread);
        new Thread(futureTask).start();
        String o = (String)futureTask.get();   //获取执行的结果,  这个get方法可能会产生阻塞!把他放在最后
        //或者使用异步通信来处理!
        System.out.println(o);

    }
}

class MyThread implements Runnable {


    @Override
    public void run() {

    }
}


class MyCallableThread implements Callable<String> {

    @Override
    public String call() throws Exception {
        return "我的返回值";
    }
}

8、常用辅助类

1、CountDownLatch

package com.example.juc.add;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"go out");
                countDownLatch.countDown();
            }, String.valueOf(i)

            ).start();
        }
        try {
            countDownLatch.await();
            System.out.println("执行完了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

原理:countDownLatch.countDown();//数量-1 countDownLatch.await();阻塞等到变为0

2、CyclicBarrier

  • public class CyclicBarrier
    extends Object
    

    允许一组线程全部等待彼此达到共同屏障点的同步辅助。循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。

    A CyclicBarrier支持一个可选的Runnable命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。

    package com.example.juc.add;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    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 temp = i;
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName()+"收集"+temp+"个龙珠");
                    try {
                        cyclicBarrier.await(); //用这个方法才加数,加了之后继续进行阻塞状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }
    

3、Semaphore

  • public class Semaphore
    extends Object
    implements Serializable
    

    一个计数信号量。在概念上,信号量维持一组许可证。如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它。每个release()添加许可证,潜在地释放阻塞获取方。但是,没有使用实际的许可证对象;Semaphore只保留可用数量的计数,并相应地执行。

    信号量通常用于限制线程数,而不是访问某些(物理或逻辑)资源

package com.example.juc.add;

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

public class SemaphoreDemo {
    public static void main(String[] args) {
        //线程数量:停车位
        Semaphore semaphore = new Semaphore(3);

        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                //acquire()得到许可证
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"抢到车位");
                try {
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release(); //release()释放许可证
                }
            },String.valueOf(i)).start();
        }

    }
}

semaphore.acquire(); 获得,假设如果已经满了,等待,等待被释放为止!

semaphore.release(); 释放,会将当前的信号量释放+1.然后唤醒等待的线程!

9、读写锁

ReadWriteLock

package com.example.juc.rw;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
    public static void main(String[] args) {

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

    }
}

/**
 * 自定义缓存
 */
class MyCache {
    private volatile Map<Integer, Object> map = new HashMap();
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public void put(Integer key, Object value) {
        try {
            readWriteLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName()+"开始存入");
            map.put(key, value);
            System.out.println(Thread.currentThread().getName()+"存入完毕");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public void get(Integer key) {
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取"+key);
            map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取完毕");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}

10、阻塞队列

队列 FIFO first in first out 先进先出

写入:如果队列满了,就必须阻塞等待

取:如果队列是空的,必须阻塞等待生产

阻塞队列:

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

package com.example.juc.bq;

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

public class Test1 {
    public static void main(String[] args) {
//        Test1.test1();
//        Test1.test2();
        try {
            Test1.test3();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 跑出异常
     */
    public static void test1() {
        //队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(arrayBlockingQueue.add("a"));
        System.out.println(arrayBlockingQueue.add("b"));
        System.out.println(arrayBlockingQueue.add("c"));

        //获取队首元素
        System.out.println(arrayBlockingQueue.peek());
        System.out.println(arrayBlockingQueue.add("d"));
    }

    /**
     * 返回false
     */
    public static void test2() {
        //队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(arrayBlockingQueue.offer("a"));
        System.out.println(arrayBlockingQueue.offer("b"));
        System.out.println(arrayBlockingQueue.offer("c"));
        System.out.println(arrayBlockingQueue.offer("d"));
    }

    /**
     * 一直阻塞
     */
    public static void test3() throws InterruptedException {
        //队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        arrayBlockingQueue.put("a");
        arrayBlockingQueue.put("b");
        arrayBlockingQueue.put("c");
//        arrayBlockingQueue.put("d");  //这里会一直阻塞
        TimeUnit.SECONDS.sleep(10);
        System.out.println(arrayBlockingQueue.take());
        System.out.println(arrayBlockingQueue.take());
        System.out.println(arrayBlockingQueue.take());
        System.out.println(arrayBlockingQueue.take()); //这里也会一直阻塞,如果没有东西了
    }

    /**
     * 超时退出
     */
    public static void test4() throws InterruptedException {
        //队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        arrayBlockingQueue.offer("a");
        arrayBlockingQueue.offer("b");
        arrayBlockingQueue.offer("c");
        arrayBlockingQueue.offer("d", 2, TimeUnit.SECONDS);  //这里等待两秒然后退出

    }
}

SynchronousQueue

同步队列:和其他的BlockingQueue不一样,它不能存储元素,put了一个元素,必须从里面先take取出来,否则不能再put进去值

11、线程池(重点)

池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我

程序的运行,本质:占用系统的资源!优化资源的使用!

线程池,连接池,内存池,对象池。。。。。。

线程池的好处:

1、降低资源的消耗

2、提高响应的速度

3、方便管理

线程复用,控制最大并发数,管理线程

线程池:三大方法

package com.example.juc.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Executors 工具类、三大方法
 * 使用了线程池之后,使用线程池来创建线程
 */
public class Demo01 {
    public static void main(String[] args) {
//        ExecutorService executorService = Executors.newFixedThreadPool(10);//固定长度
        Executors.newSingleThreadExecutor();//单个线程
        ExecutorService executorService = Executors.newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱
//        Executors.newScheduledThreadPool(10);
        for (int i = 0; i < 100; i++) {
            executorService.execute(()->
                System.out.println(Thread.currentThread().getName()+"执行了")
            );
        }
    }
}

7大参数

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
                          int maximumPoolSize,//最大核心线程池大小
                          long keepAliveTime,//超时了没人调用就会释放
                          TimeUnit unit,//超时单位
                          BlockingQueue<Runnable> workQueue, //阻塞队列
                          ThreadFactory threadFactory, //线程工厂,创建线程的,一般不用动
                          RejectedExecutionHandler handler //拒绝策略
                         ) {
}

阿里巴巴开发规范不让直接用exectors来生成线程池

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ETDo84xL-1686281371577)(图片源\image-20210419173629037.png)]

package com.example.juc.pool;

import java.util.concurrent.*;
// new ThreadPoolExecutor.AbortPolicy() 银行满了,还有人进来,不处理这个人的,抛出异常
//new ThreadPoolExecutor.CallerRunsPolicy() 哪来的去哪里
//new ThreadPoolExecutor.DiscardOldestPolicy() 队列满了,尝试去和最早的竞争,不会抛出异常
//new ThreadPoolExecutor.DiscardPolicy() 队列满了,丢掉任务,不会跑出异常
public class Demo2 {
    public static void main(String[] args) {
        //自定义线程池!工作ThreadPoolExecutor

        //最大线程应该如何定义
        //1、CPU 密集型,几核,就是几,可以保持CPU的效率最高!
        //2、IO 密集型,判断你程序中十分耗IO的线程
        //            程序  15个大型任务 io十分占用资源!
        //获取cpu的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(),
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());
        //最大承载:Deque + max
        //超过RejectedExecutionException
        for (int i = 0; i < 9; i++) {
            executorService.execute(()-> System.out.println(Thread.currentThread().getName()+"我执行了"));

        }
    }
}

最大线程如何定义:

1、CPU

//1、CPU 密集型,几核,就是几,可以保持CPU的效率最高!
//2、IO 密集型,判断你程序中十分耗IO的线程
// 程序 15个大型任务 io十分占用资源!
//获取cpu的核数
System.out.println(Runtime.getRuntime().availableProcessors());

12、四大函数式接口(必须掌握)

新时代程序员:lambda表达式,链式编程,函数式接口,Stream流式计算

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

1、function函数式接口

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
//超级多的FunctionalInterface
//简化编程模型,在新版本的框架底层大量应用!
//foreach(消费者类的函数式接口)
@FunctionalInterface
public interface Function<T, R> {  //有一个输入T,就有一个输出R

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
package com.example.juc.function;

import java.util.function.Function;

/**
 * Function 函数式接口,有一个输入参数,有一个输出
 * 只要是函数式接口,可用lambda表达式简化
 */
public class Demo01 {
    public static void main(String[] args) {
//        Function<String, String> function = new Function<String, String>() {
//            @Override
//            public String apply(String str) {
//                return str;
//            }
//        };
        Function<String, String> function = str -> str;
        System.out.println(function.apply("ddd"));
    }
}

2、predicate断定型接口:有一个输入参数,返回值只能是布尔值 !

package com.example.juc.function;

import java.util.function.Predicate;

/**
 * predicate断定型接口:有一个输入参数,返回值只能是布尔值 !
 */
public class Demo02 {
    public static void main(String[] args) {

        Predicate<String> predicate = o -> o.isEmpty();
        System.out.println(predicate.test(""));
    }
}

3、Consumer接口

package com.example.juc.function;

import java.util.function.Consumer;

public class Demo03 {
    public static void main(String[] args) {

        Consumer<String> consumer = o -> System.out.println(o);
        consumer.accept("ddddd");
    }
}

4、supplier供给型接口

package com.example.juc.function;

import java.util.function.Supplier;

public class Demo04 {
    public static void main(String[] args) {

        Supplier<String> supplier = () -> "aaa";
        System.out.println(supplier.get());
    }
}

13、stream流式计算

什么是stream流式计算

大数据:存储+计算

存储、mysql本质就是存储东西的

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

package com.example.juc.stream;

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

/**
 * 题目要求,一分钟完成此题,只能用一行代码实现!
 * 现在有5个用户,!筛选
 * 1。Id必须是偶数
 * 2、年龄必须大于23岁
 * 3、用户名转换为大写
 * 4、用户名字母倒着排序
 * 5、只能输入一个用户!
 */
public class Test {
    public static void main(String[] args) {
        User user1 = new User(1, "a", 21);
        User user2 = new User(2, "b", 21);
        User user3 = new User(3, "c", 21);
        User user4 = new User(4, "d", 21);
        User user5 = new User(5, "e", 21);
        User user6 = new User(6, "f", 21);
        List<User> list = Arrays.asList(user1, user2, user3, user4, user5, user6);
        List<User> list1 = Arrays.asList(user1, user2, user3, user4, user5, user6);
        list.stream()
                .filter(u -> u.getId() % 2 == 0)
                .filter(u -> u.getAge() > 23)
                .map(u -> u.getName().toUpperCase(Locale.ROOT))
                .sorted(String::compareTo)
                .forEach(System.out::println);
    }
}

14、ForkJoin

ForkJoin在jdk1.7,并行执行任务!提高效率,大数据量!

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

特点:工作窃取

内部维护的都是双端队列

package com.example.juc.fokjoin;

import java.util.concurrent.RecursiveTask;

/**
 * 求和计算的任务
 * 3000       6000 (FrokJoin)      9000(steam 并行流)
 */
public class ForkJoinDemo1 extends RecursiveTask<Long> {
    private Long start;
    private Long end;
    //临界值
    private Long temp = 10000L;

    public ForkJoinDemo1(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 = sum + i;
            }
//            System.out.println(sum);
            return sum;
        } else {
            //分支合并计算
            Long middle = (start + end) / 2;//中间值
            ForkJoinDemo1 task1 = new ForkJoinDemo1(start, middle);
            task1.fork();//拆分任务,把任务压入线程
            ForkJoinDemo1 task2 = new ForkJoinDemo1(middle + 1, end);
            task2.fork();
            return task1.join() + task2.join();
        }
    }
}
package com.example.juc.fokjoin;

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

public class Test {
    public static void main(String[] args) {
        Test.test1();
        Test.test2();
        Test.test3();
    }

    public static void test1() {
        long start = System.currentTimeMillis();

        Long sum = 0L;
        for (Long i = 1L; i <= 10_0000_0000L; i++) {
            sum = sum + i;
        }
        long end = System.currentTimeMillis();
        System.out.println(sum + "test1用时:" + (end - start));
    }

    public static void test2() {
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> forkJoinTask = new ForkJoinDemo1(0L,10_0000_0000L);
        ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinTask);//提交任务
        Long sum = null;
        try {
            sum = submit.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println(sum + "test2用时:" + (end - start));
    }
    public static void test3() {
        long start = System.currentTimeMillis();

        long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);

        long end = System.currentTimeMillis();
        System.out.println(sum + "test3用时:" + (end - start));
    }
}

15、异步回调

package com.example.juc.future;

import com.sun.xml.internal.ws.util.CompletedFuture;

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

/**
 * 异步调用
 */
public class Demo01 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //发起一个请求
        //没返回值的异步回调
//        CompletableFuture<Void> completedFuture = CompletableFuture.runAsync(()->{
//            try {
//                TimeUnit.SECONDS.sleep(2);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName()+"runAsync");
//        });
//        System.out.println("1111");
//        completedFuture.get();

        //有返回值的supplyAsync异步回调

        CompletableFuture<Integer> completedFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "runAsync");
            return 1024;
        });
//
        System.out.println(completedFuture.whenComplete((t, u) -> {
            System.out.println("t:" + t);
            System.out.println("u:" + u);
        }).exceptionally(e->{
            System.out.println(e.getMessage());
            return 233;
        }));

    }
}

16、JMM

请你谈谈你对Volatile的理解

Volatile是java虚拟机提供轻量级的同步机制

1、保证可见性

2、不保证原子性

3、禁止指令重排

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值