Java-JUC

1 什么是JUC

在这里插入图片描述
就是java.util包下面的三个工具类

2 进程与线程

一个进程往往可以包含多个线程,至少包含一个,
java默认2个线程,一个main线程,一个GC线程
java 不能开启进程,开启进程是要调用本地方法,java是运行在虚拟机上的没有权限开启进行。

2.1并发与并行

并发–多个线程操作同一个资源
单核,模拟出来的多线程,交替执行
并行–多个线程可以同时执行
线程池
并发编程的本质:充分利用CPU的资源

2.2 线程状态

new Thread.State();
 public enum State {
 //新建
        NEW,
//运行
        RUNNABLE,
//阻塞
        BLOCKED,
//等待
        WAITING,
//超时等待
        TIMED_WAITING,
//终止
        TERMINATED;
    }

wait() 与 sleep()

1、来自不同的类
wait()–Object
sleep–Thread
2、关于锁的释放
wait()会释放锁
sleep()不会释放
3、使用的范围不同
wait() 必须在同步代码块中使用
sleep() 可以在任何地方睡觉
4、是否需要捕获异常
wait() 不需要捕获异常
sleep()必须捕获异常

3 Lock锁(重点)

synchronized

Lock接口有三个实现类
在这里插入图片描述
Lock与synchronized的区别重点
synchronized 是java关键字,Lock是一个类
synchronized 无法判断锁的状态,Lock可以判断是否获取到锁
synchronized 会自动释放锁,Lock必须要手动释放锁!如果不释放锁,会造成死锁
synchronized 线程1(获得锁,阻塞),线程2会等待,Lock中线程不会一直等待,会尝试获取锁TrayLok()
synchronized 可重入锁,不可中断,非公平;Lock 可重入,可以判断锁,非公平(可以自己设置)
synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码

锁是什么?如何判断锁的是谁

4 生产者和消费者问题?

synchronized版

/**线程之间通信问题:生产者和消费者问题 ! 等待唤醒  通知唤醒*/
/**线程之间交替执行 A B 操作同一个变量
 * A  num+1 线程之间通信
 * B  num-1*/
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.decreament();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}
/**判断等待业务通知*/
class Data{
    private int number = 0;
    //+1
    public synchronized void increment() throws InterruptedException {
        if (number != 0){
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();
    }
    public synchronized void decreament() throws InterruptedException {
        if (number==0){
          this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();

    }
}

问题存在ABCD4个线程之后就会出现线程不安全!!
在这里插入图片描述
将if改为while条件后述情况就不会存在,由于是while()循环,所有被等待的线程在获取到cpu执行权利后一定会进行条件判断,不会出现两个生产者交替获得CPU执行权将number+1的情况(也不会出现两个消费者交替获得cpu执行权的情况)

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.decreament();
                } 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();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decreament();
                } 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);
        this.notifyAll();
    }
    public synchronized void decreament() throws InterruptedException {
        while (number==0){
          this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();

    }
}

5 JUC版本生产者消费者问题

在这里插入图片描述

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

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

    }
}

/**判断等待业务通知*/
class Data1 {
    private int number = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    //加一操作
    public synchronized void increment() throws InterruptedException {
        lock.lock();
        try {
            while (number != 0) {
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    //减一操作
    public synchronized void decreament() throws InterruptedException {
        lock.lock();
        try {
            while (number == 0) {
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }
}

重点Condition如何 精准的通知和唤醒线程

6 精准控制唤醒线程

Condition精准控制
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();

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

class Data2{
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int num = 1;
    public void printA(){
        lock.lock();
        try {
            /**当num不等于1的时候,就等待*/
            while (num != 1){
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAA");
            num = 2;
            /**处理完自己的逻辑,就唤醒指定的线程*/
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printB(){
        lock.lock();
        try {
            while (num != 2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBBBBBBBBBB");
            num = 3;
            /**处理完逻辑之后唤醒3号线程*/
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            while (num != 3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>CCCCC");
            num = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

在这里插入图片描述

7 8锁对象

小结:锁的是两个东西:new this 具体的东西
static Class 锁的是全局唯一的 Class
什么是锁,如何判断锁的是谁
锁,锁的是对象,和class
1、synchronized 锁的对象是方法的调用者
两个方法用的是同一把锁,谁先拿到谁执行
2、两个静态方法,static静态方法,类一加载就存在,Class是模板
3、一个类只有一个唯一的Class对象,全局唯一,两个对象的Class类模板只有一个。

public class Test {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            phone.cell();
        },"B").start();
    }
}

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

8 集合类不安全

方案1:使用线程安全的集合Vector,但是这个集合内部直接使用synchronized保证线程安全,导致效率低。
方案2:使用集合类的顶层接口Collections的静态内部类
方案3:CopyOnWrite 写入时复制,多个线程调用list的时候,读取是固定的,写入的时候存在覆盖的情况
在写入的避免覆盖,造成数据错误问题。
它完成了读写分离,提高效率。
CopyOnWriteArrayList 比 Vector 效率高的地方,Vector所有的方法加了synchronized效率低,CopyOnWriteArrayList 底层加的Lock锁的方式保证线程安全。

public class LlistTest {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        Vector<String> list2 = new Vector<>();//解决方案一
        List<String> list = Collections.synchronizedList(new ArrayList<>());//解决方案二
        CopyOnWriteArrayList<String> list3 = 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();
        }
    }
}

8Map线程安全

    new ConcurrentHashMap<>();
    Collections.synchronizedMap(new HashMap<>());

9 Callable 多线程

区别:有返回值,可以抛异常,方法不同call()方法
String s = futureTask.get();可能会产生阻塞,
细节:
1、有缓存
2、结果可能等待,需要阻塞

public class CallableTest {
    public static void main(String[] args) {
        Mythread mythread = new Mythread();
        //相当于一个适配类
        FutureTask<String> futureTask = new FutureTask<>(mythread);
        new Thread(futureTask,"A").start();
        try {
            String s = futureTask.get();
            System.out.println(s+"返回的");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class Mythread implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("call");
        return "123456";
    }
}

10CountDownLatch 减法计数器

原理:
downLatch.countDown();数量减一
downLatch.await();等待计数器归零,然后向下执行
每次线程调用countDown()数量就会减一,假设数量为0,countDownLatch.await()就会被唤醒,继续执行!

public class TestCountDown {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"go");
                downLatch.countDown();
            }).start();
        }
        downLatch.await();//计数器归零然后向下执行
        System.out.println("关门");
    }
}

11 cyclicBarrier 加法计数器

public class TestCyslic {
    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();
        }
    }
}

12 ReentrantReadWriteLock

独占锁(写锁) 一次只能被一个线程占有
共享锁(写锁) 多个线程可以同时占用

public class ReadWriteLockDemo {
    public static void main(String[] args) {
        //创建资源类
        DataDemo dataDemo = new DataDemo();
        //写数据
        for (int i = 1; i < 6; i++) {
            final int tmp = i;
            new Thread(() -> {
                dataDemo.write(tmp, "hello");
            }, String.valueOf(i)).start();
        }
        //读数据
        for (int i = 7; i < 11; i++) {
            final int tmp = i;
            new Thread(() -> {
                dataDemo.ride(tmp);
            }, String.valueOf(i)).start();
        }
    }
}
class DataDemo {
    private HashMap map = new HashMap();
    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void write(int key, String value) {
        //更加细粒度的锁
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "插入数据");
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "插入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public void ride(int key) {

        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "读取数据");
            map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}

10 阻塞队列

在这里插入图片描述

在这里插入图片描述
FIFO:先进先出特点。
必须阻塞的情况
写入:如果队列满了,就不许阻塞等待。
取:队列如果是空的必须等待生产。
在这里插入图片描述
使用队列:
四组API

抛出异常

add()/remove()方法会抛出异常

/**抛出异常*/
public class BlockQueue {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        //添加元素
        System.out.println(queue.add("a"));
        System.out.println(queue.add("b"));
        System.out.println(queue.add("c"));
//        System.out.println(queue.add("a"));
        System.out.println(queue.remove());
        System.out.println(queue.remove());
        System.out.println(queue.remove());
        //抛出异常
        System.out.println(queue.remove());
    }
}

不抛出异常阻塞等待

offer()添加元素/poll()删除元素,peek()判断是头元素

    private static void test2() {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        System.out.println(queue.offer("a"));
        System.out.println(queue.offer("b"));
        System.out.println(queue.offer("c"));
        System.out.println(queue.offer("d"));
        System.out.println(queue.peek()+"111");
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());

    }

阻塞等待

put()/take()

超时等待

/超时退出
public boolean offer(E e, long timeout, TimeUnit unit)
public E poll(long timeout, TimeUnit unit)

11 SynchronousQueue

同步队列:和其他队列BlockingQueue不一样,SynchronousQueue不存储元素
pub一个元素,必须从里面先取出来,否则不能put进去值。
没有容量,进去一个元素,必须等待取出来之后,才能往里面放一个元素。
put(),take()

12 线程池(重要)

创建线程的三种方式:

12.1 三大方法

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

12.2 七大参数:

   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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

12.3 四种拒绝策略

四种拒绝策略就是RejectedExecutionHandler接口下的4个实现类
在这里插入图片描述
//new ThreadPoolExecutor.AbortPolicy(); /抛异常,不接受
//new ThreadPoolExecutor.CallerRunsPolicy());//主线程执行
//new ThreadPoolExecutor.DiscardPolicy());//队列满了,不会抛出异常
//new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试和第一个任务竞争也不会抛出异常

最大的线程如何设计?
需要了解任务是cpu密集型还是io密集型

JMM

Volatile是java虚拟机提供轻量级同步机制
1、保证可见性
2、不保证原子性
3、禁止指令重排

什么是JMM:java内存模型
关于JMM的同步约定:
1、线程解锁前,必须把值刷回主存
2、线程加锁前,必须读取主存的最新值到工作内存中
3、加锁和解锁是同一把锁

线程中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值