JUD并发编程

JUC并发编程

1.什么是JUC

简称java.util.concurrent包。java并发工具包。核心是:AWT和Swing。缺点:界面不美观,需要jre环境!(界面基本都是系统窗口,运行java程序必须要安装jre,比较大!)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dLmuZcnD-1590509139192)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588767463919.png)]

业务:普通的线程代码 Thread

Runnable 没有返回值,效率相比没有Callable高。(开发主要用Callable)

2.什么是进程和线程

​ 进程:每个程序运行,系统会分配一个独立单位给程序运行,如xxx.exe这就是一个进程。 一个进程里面可以包含多个线程,至少包含一个线程。java程序中,默认有2个线程,main()启动线程和gc()垃圾回收线程。

​ 线程:是进程的单一持续控制流程。比如,一个公司是一个进程,公司每个员工从事不同的工作就是一个线程。线程不能独立存在,必须依附在某个进程。

java实现一个线程反式:继承Therad类,实现Runnable接口,实现Callable接口。

java能开启一个线程吗?

不可以,java是运行在虚拟机上的,不可以直接调用硬件,只能通过底层调用C++创建线程。

3.什么是并发和并行

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

  • ​ CPU 一核,模拟出多条线程,快速交替,看起来像是同一时间完成的。

​ 并行(多个人一行)

  • ​ CPU多核,多个程序可以同时执行。线程池。
/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 **/
public class test {
    public static void main(String[] args) {
        //获取CPU核数
        //CPU密型,IO密集合
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

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

4.线程有几种状态

6种状态:新生,运行,阻塞,等待,超时等待,终止。

源码:

 public enum State {
       //新生
        NEW,

        //运行
        RUNNABLE,

		//阻塞      
        BLOCKED,
	
        //等待
        WAITING,

     	//超时等待
        TIMED_WAITING,

        //终止
        TERMINATED;
    }

5.wait和sleep的区别

1. 不同的类

​ wait是object类,sleep是Thread类

2. 锁的释放

wait会释放锁,sleep不会释放锁。

3.使用范围不同

​ wait只能在同步代码块种使用,sleep可以任意使用。

​ 相同点:都需要捕获异常。(线程都有中断异常,可能出现超时异常)

6.Lock和synchronized区别

  1. synchronized是java内置的关键字,Lock是Java的一个类。
  2. synchronized是全自动锁,无法判断锁的状态。Lock不是全自动锁,可以获取得到锁。
  3. synchronized会自动释放锁。Lock必须手动释放锁,如果不释放锁,则会出现 死锁。(Lock锁相比synchronized安全)
  4. synchronized一旦出现阻塞,后面的线程将无法进行,就会继续等待。Lock出现阻塞不一定会等待,因为Lock的可以调用,lock.tryLock()(尝试获取锁的状态)。
  5. synchronized 可重入锁,不可中断,非公平。Lock可重入锁,可以判断锁,非公平(默认,可挑公平锁,调用RenntrantLock(true)为公平锁)公平锁:线程不可插队。非公平锁:线程可插队。
  6. synchronized适合少量代码同步问题。Lock适合大量代码同步问题。

7.生产者和消费者问题

  1. synchronized和JUC生产者和消费者问题解决反式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrRFyivy-1590509139194)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588844060221.png)]

  1. synchronized版 wait() ;(等待) notifyAll();(通知所有线程可启动)

/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 *
 **/
public class test {

    public static void main(String[] args) {
        Date a=new Date();

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

    }
}


class  Date{ //等待,业务,通知
    private  int count=0;

    public synchronized void A() throws InterruptedException {
        //判断 是否等待
        if (count!=0){
            this.wait();
        }
        //业务 模块
        count++;
        System.out.println(Thread.currentThread().getName()+"="+count);
        //通知其他线程启动
        this.notifyAll();
    }
    public synchronized void B() throws InterruptedException {
        //判断 是否等待
        if (count==0){
            this.wait();
        }
        //业务 模块
        count--;
        System.out.println(Thread.currentThread().getName()+"="+count);
        //通知其他线程启动
        this.notifyAll();
    }
}

问题:如果出现2个以上的线程同时调用一个资源如何处理?

将if判断改为while判断。(因为if只会判断一次,条件满足后就不会再次判断,whlie是循环,每次都会判断。防止虚假唤醒)

/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 *
 **/
public class test {

    public static void main(String[] args) {
        Date a=new Date();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                try {
                    a.A();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"线程A").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                try {
                    a.A();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"线程B").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                try {
                    a.B();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"线程C").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                try {
                    a.B();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"线程D").start();

    }
}


class  Date{ //等待,业务,通知
    private  int count=0;
    //+1
    public synchronized void A() throws InterruptedException {
        //判断 是否等待
        while (count!=0){
            this.wait();
        }
        //业务 模块
        count++;
        System.out.println(Thread.currentThread().getName()+"="+count);
        //通知其他线程启动
        this.notifyAll();
    }
    // -1
    public synchronized void B() throws InterruptedException {
        //判断 是否等待
        while (count==0){
            this.wait();
        }
        //业务 模块
        count--;
        System.out.println(Thread.currentThread().getName()+"="+count);
        //通知其他线程启动
        this.notifyAll();
    }
}

  1. Lock版Lock lock=new ReentrantLock();Condition condition=lock.newCondition();,condition.awit();(等待),condition.signalAll();(唤醒全部)。
package com.yp.task;

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

/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 *
 **/
public class test {

    public static void main(String[] args) {
        Date a=new Date();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                a.A();
            }
        },"线程A").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
               a.A();
            }
        },"线程B").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
               a.B();
            }
        },"线程C").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                    a.B();
            }
        },"线程D").start();

    }
}

class  Date{ //等待,业务,通知
    //Lock 取代了 synchronized Condition取代了对象监视器方法(synchronized的wetia、notify和notifyAll)
    Lock lock=new ReentrantLock();
    Condition condition=lock.newCondition();
    private  int count=0;
    //+1
    public  void A()  {
        lock.lock();//上锁
        try {
            //判断 是否等待
            while (count!=0){
                condition.await();//等待
            }
            //业务 模块
            count++;
            System.out.println(Thread.currentThread().getName()+"="+count);
            //通知其他线程启动
            condition.signalAll();//唤醒全部
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁
        }
    }
    // -1
    public  void B(){
        lock.lock();//上锁
            try {
                //判断 是否等待
                while (count==0){
                condition.await();//等待
                }
                //业务 模块
                count--;
                System.out.println(Thread.currentThread().getName()+"="+count);
                //通知其他线程启动
                condition.signalAll();//唤醒全部
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//释放锁
            }
    }
}

Condition可以精准的唤醒某个线程。

package com.yp.task;

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

/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 *
 **/
public class test {

    public static void main(String[] args) {
        Date a=new Date();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                a.A();
            }
        },"线程A").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
               a.B();
            }
        },"线程B").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
               a.C();
            }
        },"线程C").start();
        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                    a.D();
            }
        },"线程D").start();

    }
}

class  Date{ //等待,业务,通知
    //Lock 取代了 synchronized Condition取代了对象监视器方法(synchronized的wetia、notify和notifyAll)
    Lock lock=new ReentrantLock();
    //创建多个Condition 监视多个线程
    Condition condition1=lock.newCondition();
    Condition condition2=lock.newCondition();
    Condition condition3=lock.newCondition();
    Condition condition4=lock.newCondition();
    private  int count=1;
   
    public  void A()  {
        lock.lock();//上锁
        try {
            //判断 是否等待
            while (count!=1){
                condition1.await();//等待
            }
            //业务 模块
            count=2;
            System.out.println(Thread.currentThread().getName()+"="+count+",通知B执行");
            //通知其他线程启动
            condition2.signal();//唤醒B
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁
        }
    }
   
    public  void B(){
        lock.lock();//上锁
            try {
                //判断 是否等待
                while (count!=2){
                condition2.await();//等待
                }
                //业务 模块
                count=3;
                System.out.println(Thread.currentThread().getName()+"="+count+",通知C执行");
                //通知其他线程启动
                condition3.signal();//唤醒C
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//释放锁
            }
    }
    public  void C()  {
        lock.lock();//上锁
        try {
            //判断 是否等待
            while (count!=3){
                condition3.await();//等待
            }
            //业务 模块
            count=4;
            System.out.println(Thread.currentThread().getName()+"="+count+",通知D执行");
            //通知其他线程启动
            condition4.signal();//唤醒D
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁
        }
    }
    
    public  void D(){
        lock.lock();//上锁
        try {
            //判断 是否等待
            while (count!=4){
                condition4.await();//等待
            }
            //业务 模块
            count=1;
            System.out.println(Thread.currentThread().getName()+"="+count+",通知A执行");
            //通知其他线程启动
            condition1.signal();//唤醒A
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁
        }
    }
}

可用用在一条业务生产线 如:下单>支付>交易成功>物流等。

8.八锁现象

视频链接:https://www.bilibili.com/video/BV1B7411L7tE?p=10

小结:new this 是一个具体的手机。static Class 是唯一的模板。

9.集合类不安全

1. 为什么ArrayList在高并发情况下不安全?如何解决?

    public static void main(String[] args) {
    /*
    *       OM内存溢出异常
    * 使用  ArrayList<>() 运行报错 java.util.ConcurrentModificationException(并发修改异常)
    * 1.可使用 List<String> list=new Vector<>(); (可以解决并发问题,使用的synchronized锁,效率没有ArrayList高)
    * 2.可使用 List<String> list= Collections.synchronizedList(new ArrayList<>());(将ArryList转换为安全的)
    * 3.使用 List<String> list= new CopyOnWriteArrayList<>(); (推荐使用,使用的Lock锁)			*CopyOnWrite 写入时复制 COW思想 计算机程序设计邻域的一种优化策略
    *多线程调用list的时候,list读取的时候,固定的,写入(覆盖)
    *在写入的时候避免覆盖,造成数据问题
    * */
        List<String> list= new CopyOnWriteArrayList<>();
        for (int i = 0; i <10 ; i++) {
            new Thread(()->{
                    list.add(UUID.randomUUID().toString().substring(0,5));//UUID.randomUUID().toString().substring(0,5) 创建5个随机数
                    System.out.println(list);
            },String.valueOf(i)).start();
        }
    }

2.HashSet和ArrayList的区别?HashSet底层是什么?如何使HashSet安全?

​ HashSet无序,ArrayList有序,都是不安全的。HashSet底层就是HashMap,HashSet.add调用的就是HasMap.put方法保存的键就是hasSet的值,所以是唯一的。ArryList值是可重复的。

和上面一样,使用工具类Collections.synchronizedSet()转换成安全的,使用CopyOnWriteArraySet<>()。

3.HashMap

1. 工作种HashMap是这样使用的吗Map<String,Object> map=new HashMap();?默认等价是什么?

不是,企业中不用HashMap,应为HashMap不安全,一般使用Map(String,String) map=new ConcurrentHashMap<>();

默认等价是:new HashMap<>(16,0.75);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZrYSfGBy-1590509139196)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588868782460.png)]

10.Callable

  1. Callable和Runnable一样,但是Callable可以有返回值,可以捕获异常。
  2. 方法不同,run()。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PlNIbnUz-1590509139199)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588939404164.png)]


/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 *
 **/
public class test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        
        MyCallable myCallable=new MyCallable();
        FutureTask task=new FutureTask(myCallable); // 适配类 FutureTask 是 Runnable的子类
        new Thread(task,"A").start();

        System.out.println("返回值为:"+task.get());//接受返回值  可能会出现阻塞,可以把它反倒最后或			//者使用异步通信
    }


}
class  MyCallable implements  Callable<String>{  //可设置返回值
    @Override
    public String call() throws Exception {
        System.out.println("进来了!");
        return "OK";
    }
}

细节:

  1. Callable会有缓存。
  2. 调用sask.get()时可能会发生阻塞,因为要接受返回值。

11. JUC常用的3大辅助类

1. CountDowLath(减法计数器)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SOZRkq4T-1590509139200)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1588941389551.png)]

 public static void main(String[] args) throws ExecutionException, InterruptedException {
                //计数器 总数6次 必须要执行任务的是,再使用
                CountDownLatch countDownLatch=new CountDownLatch(6);
                    for (int i = 0; i < 6; i++) {
                        new Thread(()->{
                            System.out.println(Thread.currentThread().getName());
                            //每执行一个线程countDownLatch -1
                            countDownLatch.countDown();
                        },String.valueOf(i)).start();

                    }
                    //等待线程执行完 再执行后面任务
                    countDownLatch.await();// 等待

                System.out.println("执行玩,关门!");

    }

原理

​ CountDwoLatch主要就countDownLatch.countDown(); //-1 不会阻塞,和 countDownLatch.await();// 等待归零然后执行下面的。每次有线程调用countDown();-1,假设计数器变为0,countDownLatch将被唤醒 继续执行。

2. CyclicBarrnier(加法计数器)

​ 和减法计数器差不多。

/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 *
 **/
public class test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
                CyclicBarrier cyclicBarrier=new CyclicBarrier(8,()->{
                    System.out.println("到齐了,关门!");
                });

            for (int i = 1; i <= 8; i++) {
                final int b=i;  //细节:这里用lomedak表达式里面是接受不到外循环的i 的 再外面定义final 变量接受一下就可以
                new Thread(()->{
                    System.out.println("第:"+b+"个");

                    try {
                        cyclicBarrier.await(); //等待 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
    }


}

3. Semaphore(信号量)

​ 例子:停车位,3个停车位,6辆车。

​ semaphore.acquire()等待,semaphore.release()释放。设置资源线程数量,然后等待释放。


    public static void main(String[] args) throws ExecutionException, InterruptedException {
                Semaphore semaphore=new Semaphore(3);//这里的3 代表3个线程 也就是3个车位
                //创建6个线程
        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                try {
                    //首先获取资源 (抢占资源)
                    semaphore.acquire(); //等待
                    //输出谁拿到了车位
                    System.out.println(Thread.currentThread().getName()+"拿到了车位!");
                    //模拟真实业务,停留2秒
                    TimeUnit.SECONDS.sleep(2);
                    //输出离开
                    System.out.println(Thread.currentThread().getName()+"离开了车位!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //释放资源
                    semaphore.release();//释放
                }
            },String.valueOf(i)).start();
        }

    }

12.ReadWriteLock

​ 读写锁,读的时候可以多个线程读,写的时候只能一条线程写。

​ 独占锁(写锁):一次只能被一个线程占有。

​ 共享锁(读锁):多个线程可以同时占有。

​ readWriteLock

​ 读-读:可存。

​ 写-读:不可存。

​ 写-写:不可存。

readWriteLock.writeLock()写 锁  ,readWriteLock.readLock()读锁
package com.yp.task;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

/**
 * @Developer 大都督
 * @date 2020/5/6 20:57
 *
 **/
public class test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyReadWriteLock myReadWriteLock=new MyReadWriteLock();
        //5个线程写
        for (int i = 1; i <=5 ; i++) {
            final  int a=i;
            new Thread(()->{

                myReadWriteLock.set(String.valueOf(a),String.valueOf(a+a));
            },String.valueOf(i)).start();
        }
        //5个线程读
        for (int i = 1; i <=5 ; i++) {
            final  int a=i;
            new Thread(()->{

                myReadWriteLock.get(String.valueOf(a));
            },String.valueOf(i)).start();
        }


    }


}
class  MyReadWriteLock{  //可设置返回值   readWriteLock.writeLock()写 锁  ,readWriteLock.readLock()读锁
        private Map<String,String> map=new ConcurrentHashMap(); //假设是个缓存
        ReadWriteLock readWriteLock=new ReentrantReadWriteLock(); //读写锁

        //写
        public void set(String k,String v){

            try {
                //读 加锁
                readWriteLock.writeLock().lock();
                //业务 将数据写入
                System.out.println(Thread.currentThread().getName()+"在写"+v);
                map.put(k,v);
                System.out.println(Thread.currentThread().getName()+"写入完成!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放锁
                readWriteLock.writeLock().unlock();
            }
        }

        // 读
        public void get(String k){
            try {
                readWriteLock.readLock().lock();
                System.out.println(Thread.currentThread().getName()+"在读"+k);
                map.get(k);
                System.out.println(Thread.currentThread().getName()+"读取完成!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放锁
                 readWriteLock.readLock().unlock();
            }
        }

}

13.阻塞队列(BlockingQueue)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOFdX2Yx-1590509139203)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1589015610224.png)]

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

阻塞队列4组API:

方式抛出异常不会抛出异常阻塞等待超时等待
添加add()offer()put()offer(“元素”,3,2, TimeUnit.SECONDS)
移除remove()poll()take()poll(2, TimeUnit.SECONDS)
检测首元素element()peek()可能会出现等待,所以不存在检测可能会出现等待,所以不存在检测
  1. public class Test {
    
        public static void main(String[] args) {
            //抛出异常
            MyblockingQueue();
        }
    
        public static void MyblockingQueue(){
            BlockingQueue blockingQueue=new ArrayBlockingQueue(3);//设置阻塞队列长度
            System.out.println(blockingQueue.add("A"));
            System.out.println(blockingQueue.add("B"));
            System.out.println(blockingQueue.add("C"));
            //java.lang.IllegalStateException: Queue full 添加超出队列长度抛出异常
            //System.out.println(blockingQueue.add("D"));
    
            System.out.println("============================");
            System.out.println(blockingQueue.remove());
            System.out.println(blockingQueue.remove());
            System.out.println(blockingQueue.remove());
            //java.util.NoSuchElementException 移除超出队列长度抛出异常
            //System.out.println(blockingQueue.remove());
    
        }
    
    }
    
    1. package com.yb.sampleyest;
      
      import java.util.concurrent.ArrayBlockingQueue;
      import java.util.concurrent.BlockingQueue;
      
      /**
       * @Developer 大都督
       * @date 2020/5/24 16:09
       **/
      public class Test {
      
          public static void main(String[] args) {
              //不抛出异常
              MyblockingQueue();
          }
      
          public static void MyblockingQueue(){
              BlockingQueue blockingQueue=new ArrayBlockingQueue(3);//设置阻塞队列长度
              System.out.println(blockingQueue.offer("A"));
              System.out.println(blockingQueue.offer("B"));
              System.out.println(blockingQueue.offer("C"));
              //返回false 不报错
              //System.out.println(blockingQueue.offer("D"));
              System.out.println("============================");
              System.out.println(blockingQueue.poll());
              //peek()获取列首
              System.out.println("首队列:"+blockingQueue.peek());
              System.out.println(blockingQueue.poll());
              System.out.println(blockingQueue.poll());
              //返回null 不抛出异常
              System.out.println(blockingQueue.poll());
          }
      }
      
  2. package com.yb.sampleyest;
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    
    /**
     * @Developer 大都督
     * @date 2020/5/24 16:09
     **/
    public class Test {
    
        public static void main(String[] args) throws InterruptedException {
            //一直阻塞
            MyblockingQueue();
        }
    
        public static void MyblockingQueue() throws InterruptedException {
            ArrayBlockingQueue blockingQueue=new ArrayBlockingQueue(3);//设置阻塞队列长度
                    //没有返回值
                    blockingQueue.put("A");
                    blockingQueue.put("B");
                    blockingQueue.put("C");
                    //队列没有位置了 会一直阻塞
                    // blockingQueue.put("C");;
                    System.out.println("============================");
                    System.out.println(blockingQueue.take());
                    //peek()获取列首
                    System.out.println("首队列:"+blockingQueue.peek());
                    System.out.println(blockingQueue.take());
                    System.out.println(blockingQueue.take());
                    //队列没有这个元素,会一直阻塞
                    System.out.println(blockingQueue.take());
        }
    }
    
    package com.yb.sampleyest;
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Developer 大都督
     * @date 2020/5/24 16:09
     **/
    public class Test {
    
        public static void main(String[] args) throws InterruptedException {
            //超时等待
            MyblockingQueue();
        }
    
        public static void MyblockingQueue() throws InterruptedException {
            ArrayBlockingQueue blockingQueue=new ArrayBlockingQueue(3);//设置阻塞队列长度
                System.out.println(blockingQueue.offer("A"));
                System.out.println(blockingQueue.offer("B"));
                System.out.println(blockingQueue.offer("C"));
                //设置超时时间,如果超过时间将放回flase
                System.out.println("超时等待:"+blockingQueue.offer("C", 2, TimeUnit.SECONDS));;
                System.out.println("============================");
                System.out.println(blockingQueue.poll());
                //peek()获取列首
                System.out.println("首队列:"+blockingQueue.peek());
                System.out.println(blockingQueue.poll());
                System.out.println(blockingQueue.poll());
                //设置超时间,如果超出时间没有该元素,将返回null
                System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
        }
    }
    
    

14.SynchronousQueue(同步队列)

  1. 与BlockingQueue(阻塞队列)不同,SynchronousQueue(同步队列)不可设置长度(相当于只能存一个元素),put一个元素之后,必须take取出,否则后面不能put值进去。
package com.yb.sampleyest;

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

/**
 * @Developer 大都督
 * @date 2020/5/24 16:09
 **/
public class Test {

    public static void main(String[] args){
       //同步队列  必须取完才能继续添加
        BlockingQueue<String> synchronousQueue=new SynchronousQueue<>();
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"\tput\tA");
                //添加同步元素
                synchronousQueue.put("A");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                System.out.println(Thread.currentThread().getName()+"\tput\tB");
                //添加同步元素
                synchronousQueue.put("B");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                System.out.println(Thread.currentThread().getName()+"\tput\tC");
                //添加同步元素
                synchronousQueue.put("C");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        new Thread(()->{
            try {
                //模仿实际场景,阻塞2秒
                TimeUnit.SECONDS.sleep(2);
                //取出元素
                System.out.println( Thread.currentThread().getName()+"\ttake\t"+synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                //模仿实际场景,阻塞2秒
                TimeUnit.SECONDS.sleep(2);
                //取出元素
                System.out.println( Thread.currentThread().getName()+"\ttake\t"+synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                //模仿实际场景,阻塞2秒
                TimeUnit.SECONDS.sleep(2);
                //取出元素
                System.out.println( Thread.currentThread().getName()+"\ttake\t"+synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"B").start();;
    }
}

15.线程池

线程池:3大方法,7大参数,4种拒绝策略。

池化技术:程序运行时,本质占用的系统资源,优化资源的使用。(概念:事先准备好一些资源,有人要用,就来拿,用完之后还给我。)

线程池的好处(优点):
  1. 降低资源消耗。
  2. 提高响应速度。
  3. 方便管理。
  4. 线程复用,可以控制最大并发数,管理线程。

1. 第一种反式

使用Executors 工具类

Executors 三大方法(不推荐使用,不要问为什么,问就是阿里巴巴程序员开发手册说的。推荐使用 ExecutorService底层调用的ThreadPoolExecutor方法,其实也就是内部定义值太大,可能出现oom内存溢出异常。):

package com.yb.sampleyest;

import java.util.concurrent.*;

/**
 * @Developer 大都督
 * @date 2020/5/24 16:09
 **/
public class Test {

    public static void main(String[] args) {
       ExecutorService executors= Executors.newSingleThreadExecutor();//单个线程 Single(单个)

//        Executors.newFixedThreadPool(5);//创建一个固定的线程池大小 Fixed(固定的)
//        Executors.newCachedThreadPool();//可伸缩大小,遇强则强,遇弱则弱。 Cached(缓存)
        //使用线程池创建10个线程
        try {
            for (int i = 0; i <10 ; i++) {
                executors.execute(()->{ //创建一个线程
                    System.out.println(Thread.currentThread().getName()+"线程执行完毕!");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executors.shutdown();
        }
    }


}

2. 第二种反式

ExecutorService底层调用的ThreadPoolExecutor方法。(7大参数)

源码(在1303行,有好几个重载方法!):

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

事例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PtR3phal-1590509139204)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1590504832716.png)]

代码:

package com.yb.sampleyest;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.*;

/**
 * @Developer 大都督
 * @date 2020/5/24 16:09
 **/
public class Test {

    public static void main(String[] args) {
        //默认3条线程,最大线程5,超时等待2秒,等待区域3条线程,超出最大线程池的大小并且阻塞队列满了线程抛出异常
       ExecutorService executors= new ThreadPoolExecutor(3, //线程池大小
               5, //最大线程池
               2, //超时等待
               TimeUnit.SECONDS, //超时等待单位
               new LinkedBlockingDeque<>(3),//阻塞队列
              Executors.privilegedThreadFactory(),//线程工厂
//              new ThreadPoolExecutor.AbortPolicy() //默认的拒绝策略   超出最大线程池的大小,阻塞队列满了 ,不处理,抛出异常
//               new ThreadPoolExecutor.CallerRunsPolicy()//队列满了,哪里来的回哪里
//               new ThreadPoolExecutor.DiscardPolicy()//队列满了,丢掉任务,不会抛出异常
               new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了,它会尝试和最早的线程竞争(也就看最早的线程执行完毕没有),如果最早线程结束了,那它就可以执行,如果还没结束,那任务就丢掉,不会抛出异常
       );

        //使用线程池创建10个线程
        try {
            for (int i = 0; i <20 ; i++) {
                executors.execute(()->{ //创建一个线程
                    System.out.println(Thread.currentThread().getName()+"线程执行完毕!");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executors.shutdown();
        }
    }


}

4种拒绝策略:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KHJljl8f-1590509139205)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1590506079165.png)]

16.IO密集型和CPU密集型(调优)

  1. IO密集型:大于判断你程序中十分耗IO的线程x2倍在左右。(程序有10条线程非常耗IO,那最大值就20条线程)
  2. CPU密集型:你电脑几核,就是几核,可以保持CPU效率最高。java代码获取cpu核数:
   //获取本地电脑cpu核数
     System.out.println(Runtime.getRuntime().availableProcessors());

ngDeque<>(3),//阻塞队列
Executors.privilegedThreadFactory(),//线程工厂
// new ThreadPoolExecutor.AbortPolicy() //默认的拒绝策略 超出最大线程池的大小,阻塞队列满了 ,不处理,抛出异常
// new ThreadPoolExecutor.CallerRunsPolicy()//队列满了,哪里来的回哪里
// new ThreadPoolExecutor.DiscardPolicy()//队列满了,丢掉任务,不会抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了,它会尝试和最早的线程竞争(也就看最早的线程执行完毕没有),如果最早线程结束了,那它就可以执行,如果还没结束,那任务就丢掉,不会抛出异常
);

    //使用线程池创建10个线程
    try {
        for (int i = 0; i <20 ; i++) {
            executors.execute(()->{ //创建一个线程
                System.out.println(Thread.currentThread().getName()+"线程执行完毕!");
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        executors.shutdown();
    }
}

}


4种拒绝策略:

[外链图片转存中...(img-KHJljl8f-1590509139205)]

## 16.IO密集型和CPU密集型(调优)

1. IO密集型:大于判断你程序中十分耗IO的线程x2倍在左右。(程序有10条线程非常耗IO,那最大值就20条线程)
2. CPU密集型:你电脑几核,就是几核,可以保持CPU效率最高。java代码获取cpu核数:

```java
   //获取本地电脑cpu核数
     System.out.println(Runtime.getRuntime().availableProcessors());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值