JUC并发编程(二)

JUC并发编程(二)

七. Callable

在这里插入图片描述
1.可以有返回值,可以抛出异常,方法不同

例子:

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 Runable()).start();
        //new Thread(new FutureTask<V>()).start();
        //new Thread(new FutureTask<>(Callable)).start();
        new Thread().start();  //如何启动Callable
        MyThread thread = new MyThread();
        FutureTask futureTask = new FutureTask(thread); //适配类
        new Thread(futureTask,"A").start();
        Integer o = (Integer)futureTask.get(); //返回callable的返回结果
        //get可能会产生阻塞,把它放到最后,或者使用异步通信
        System.out.println(o);
    }
}

class MyThread implements Callable<Integer>{

    @Override
    public Integer call(){
        System.out.println("call");
        return 1024;
    }
}

八. 常用辅助类(必会)

8.1.CountDownLatch 减法计数器

import java.util.concurrent.CountDownLatch;

//减法计数器
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        //总数是六的倒计时
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for (int i = 1; i <= 5; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" Go Out");
                countDownLatch.countDown();//数量减一
            },String.valueOf(i)).start();
        }
        countDownLatch.await();//等待计数器归零 ,然后再向下执行
        System.out.println("close door");
    }
}

原理:
countDownLatch.countDown();//数量减一
countDownLatch.await();//等待计数器归零
每次有线程调用 countDown() ,计数器数量将减一,计数器变为零则countDownLatch.await();就会被唤醒继续执行

8.2 CyclicBarrier 加法计数器

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

public class CyclicBarrierDemo {
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("end");
        });
        for (int i = 1; i <= 7; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"++");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

8.3 Semaphore 信号量

  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 = 1; i <= 6; i++) {
            new Thread(()->{
                try {
                    semaphore.acquire();//得到
                    System.out.println(Thread.currentThread().getName()+"抢到车位");
                    TimeUnit.SECONDS.sleep(2);//车停一段时间
                    System.out.println(Thread.currentThread().getName()+"离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();//释放
                }
            },String.valueOf(i)).start();
        }
    }
}

原理:
semaphore.acquire();//获取 假设如果已经满了,就等待资源被释放为止
semaphore.release();//释放 将当前的信号量释放+1,然后唤醒等待的线程
作用:多个共享资源互斥使用,并发限流,控制最大线程数

九. 读写锁 ReadWriteLock

在这里插入图片描述
无锁实例:

import java.util.HashMap;
import java.util.Map;


/**
 * ReadWriteLock
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        MyCacheLock myCacheLock = 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.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}
//自定义缓存,一 :set  二:put
//无锁
class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    //存  写
    public void put(String key,Object value){
        System.out.println(Thread.currentThread().getName()+"写入.");
        map.put(key, value);
        System.out.println(Thread.currentThread().getName()+"写入完毕.");
    }
    //取  读
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"读取"+key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取完毕.");
    }
}
结果:
1写入.
4写入.
3写入.
3写入完毕.
2写入.
1写入完毕.
5写入.
4写入完毕.
5写入完毕.
2写入完毕.
3读取3
3读取完毕.
1读取1
2读取2
2读取完毕.
4读取4
1读取完毕.
4读取完毕.
5读取5
5读取完毕.

加锁实例:

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

/**
 * ReadWriteLock
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCacheLock myCacheLock = new MyCacheLock();
        //加锁,写入操作
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCacheLock.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        //加锁,读操作
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCacheLock.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}
//自定义缓存,一 :set  二:put
//加锁
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()+"写入.");
            map.put(key, value);
            System.out.println(Thread.currentThread().getName()+"写入完毕.");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }
    //取  读的时候,所有人都可以读
    public void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取");
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取完毕.");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}
结果:
1写入.
1写入完毕.
2写入.
2写入完毕.
4写入.
4写入完毕.
3写入.
3写入完毕.
5写入.
5写入完毕.
5读取
1读取
4读取
1读取完毕.
3读取
3读取完毕.
2读取
2读取完毕.
5读取完毕.
4读取完毕.

讲解:
一:ReadWriteLock分为三种情况
读-读 可以共存
读-写 不能共存
写-写 不能共存
二:独占锁(写锁) 一次只能被一个线程占有
共享锁(读锁) 多个线程可以同时占有

十. 阻塞队列

阻塞
队列

在这里插入图片描述

分类:
BlockingDeque 阻塞队列
AbstractQueue 非阻塞队列
Deque 双端队列

10.1 BlockingQueue(阻塞队列)

在这里插入图片描述

什么情况下需要用到阻塞队列:多线程线程处理,线程池

使用队列:添加,删除 四组API
1.抛出异常
2.不会抛出异常
3.阻塞等待
4.超时等待

方式抛出异常有返回值,不抛异常阻塞 等待超时等待
添加addofferputoffer(带参)
移除removepolltakepoll(带参)
检测队首元素elementpeek
抛出异常
//抛出异常  
import java.util.concurrent.ArrayBlockingQueue;

public class Test {
    public static void main(String[] args) {
        //Collection
        test1();
    }

    public static void test1(){
        //队列的大小为3
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
        //添加第四个数据,会抛出异常Queue full
        //System.out.println(blockingQueue.add("d"));

		//判断队首
        System.out.println(blockingQueue.element());
        
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //移除空数据  抛出异常.NoSuchElementException
        //System.out.println(blockingQueue.remove());
    }
}
---------------结果---------------
true
true
true
a
a
b
c
有返回值,不抛异常
//有返回值,不抛异常
import java.util.concurrent.ArrayBlockingQueue;

public class Test {
   public static void main(String[] args) {
       //Collection
       test2();
   }

   public static void test2(){
       //队列大小3
       ArrayBlockingQueue 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(blockingQueue.peek());

       System.out.println(blockingQueue.poll());
       System.out.println(blockingQueue.poll());
       System.out.println(blockingQueue.poll());
       //不抛出异常,返回null
       System.out.println(blockingQueue.poll());
   }
}
---------------结果---------------
true
true
true
false
a
a
b
c
null
阻塞 等待
//阻塞 等待(一直等待)
import java.util.concurrent.ArrayBlockingQueue;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        //Collection
        test3();
    }
    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());
    }
}
超时等待
//阻塞 等待(超时退出)
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

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

    public static void test4() 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"));
        //没有位置,阻塞 等待 (超时退出)
        System.out.println(blockingQueue.offer("d", 2, TimeUnit.SECONDS));//两秒后退出
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        //没有元素,阻塞等待 (超时退出)
        System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));//两秒后退出
    }
}

10.2 synchronizedQueue(同步队列)

没有容量
进去一个元素,必须取出来之后,才能再往里放入一个元素

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

public class synchronizedQueueDemo {
    public static void main(String[] args) {
        //同步队列
        SynchronousQueue synchronousQueue= new SynchronousQueue<>();
        new Thread(()->{

            try {
                System.out.println(Thread.currentThread().getName()+" put 1 ");
                synchronousQueue.put("1");
                System.out.println(Thread.currentThread().getName()+" put 2 ");
                synchronousQueue.put("2");
                System.out.println(Thread.currentThread().getName()+" put 3  ");
                synchronousQueue.put("3");

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T1").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + " take " + synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + " take " + synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + " take " + synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T2").start();
    }
}
---------------结果---------------
T1 put 1 
T2 take 1
T1 put 2 
T2 take 2
T1 put 3 
T2 take 3

十一. 线程池(重点)

池化技术

程序的运行,本质:占用系统的资源!优化资源的使用!=>池化技术
线程池,连接池,内存池,对象池,常量池…

线程池的好处:
1.降低资源的消
2.提高响应速度
3.方便管理

线程复用,控制最大并发数,管理线程
必会的一些东西:三大方法,七大参数,四种拒绝策略

在这里插入图片描述

11.1三大方法

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

public class Demo01 {
    public static void main(String[] args) {
        //Executors 工具类,三大方法
        ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个
        //ExecutorService threadPool = Executors.newFixedThreadPool(5);  //创建一个固定的线程池的大小
        //ExecutorService threadPool = Executors.newCachedThreadPool();  //可变的
        try {
            for (int i = 0; i < 7; i++) {
                //不用new thread,而是从线程池取
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"--");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完要关闭
            threadPool.shutdown();
        }
    }
}
---------------依次执行三种方法结果---------------
---------------newSingleThreadExecutor()---------------
pool-1-thread-1--
pool-1-thread-1--
pool-1-thread-1--
pool-1-thread-1--
pool-1-thread-1--
pool-1-thread-1--
pool-1-thread-1--
---------------Executors.newFixedThreadPool(5)---------------
pool-1-thread-1--
pool-1-thread-4--
pool-1-thread-1--
pool-1-thread-3--
pool-1-thread-2--
pool-1-thread-4--
pool-1-thread-5--
---------------Executors.newCachedThreadPool()---------------
pool-1-thread-2--
pool-1-thread-5--
pool-1-thread-4--
pool-1-thread-3--
pool-1-thread-1--
pool-1-thread-6--
pool-1-thread-7--

11.2 七大参数

源码分析
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
三个不同的方法,调用的都是ThreadPoolExecutor
在ThreadPoolExecutor中可以看到,这七个参数
在这里插入图片描述

int corePoolSize 核心线程大小
int maximumPoolSize 最大核心线程池大小
long keepAliveTime 空闲线程存活时间
TimeUnit unit 超时单位
BlockingQueue workQueue, 阻塞队列
ThreadFactory threadFactory, 线程工厂,创建线程的
RejectedExecutionHandler handler 拒绝策略

在这里插入图片描述
所以在上面不允许使用Executor来创建线程,避免资源耗尽

接下来我们手动创建一个线程池,来

11.4四种拒绝策略

在这里插入图片描述
这四条就是我们说的四种拒绝策略

//第一种拒绝策略
import java.util.concurrent.*;

public class Demo02 {
    public static void main(String[] args) {
        //自定义线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                3, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                //第一种拒绝策略
                new ThreadPoolExecutor.AbortPolicy());//如果超出8个线程,不处理,线程就会报错,抛出异常
        try {
            //最大承载 = Deque + max
            //超出最大承载就会抛出:RejectedExecutionException异常,被拒绝策略异常
            for (int i = 0; i < 9; i++) {
                //不用new thread,而是从线程池取
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"--");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完要关闭
            threadPool.shutdown();
        }
    }
}
---------------结果---------------
pool-1-thread-2--
pool-1-thread-4--
pool-1-thread-2--
pool-1-thread-3--
pool-1-thread-1--
pool-1-thread-2--
pool-1-thread-4--
pool-1-thread-5--
java.util.concurrent.RejectedExecutionException: 
//第二种拒绝策略
import java.util.concurrent.*;

public class Demo02 {
    public static void main(String[] args) {
        //自定义线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                3, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                //第二种拒绝策略
                new ThreadPoolExecutor.CallerRunsPolicy()); //那里来的去那里
        try {
            //最大承载 = Deque + max
            //超出最大承载就会抛出:RejectedExecutionException异常,被拒绝策略异常
            for (int i = 0; i < 9; i++) {
                //不用new thread,而是从线程池取
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"--");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完要关闭
            threadPool.shutdown();
        }
    }
}
---------------结果---------------
pool-1-thread-1--
pool-1-thread-5--
pool-1-thread-3--
pool-1-thread-2--
pool-1-thread-3--
pool-1-thread-4--
main--
pool-1-thread-5--
pool-1-thread-1--
//第三种拒绝策略
import java.util.concurrent.*;

public class Demo02 {
    public static void main(String[] args) {
        //自定义线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                3, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                //第三种拒绝策略
                new ThreadPoolExecutor.DiscardPolicy()); //队列满了,丢掉任务,不会抛出异常
        try {
            //最大承载 = Deque + max
            //超出最大承载就会抛出:RejectedExecutionException异常,被拒绝策略异常
            for (int i = 0; i < 9; i++) {
                //不用new thread,而是从线程池取
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"--");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完要关闭
            threadPool.shutdown();
        }
    }
}
---------------结果---------------
pool-1-thread-2--
pool-1-thread-4--
pool-1-thread-3--
pool-1-thread-1--
pool-1-thread-3--
pool-1-thread-4--
pool-1-thread-5--
pool-1-thread-2--

抛弃队列里最老的那个,代替他的位置进入队列里

//第四种拒绝策略
import java.util.concurrent.*;

public class Demo02 {
    public static void main(String[] args) {
        //自定义线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                3, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                //第四种拒绝策略
                new ThreadPoolExecutor.DiscardOldestPolicy()); //试探最早的线程是否结束,如果结束就跟进,没结束不处理,不会抛出异常
        try {
            //最大承载 = Deque + max
            //超出最大承载就会抛出:RejectedExecutionException异常,被拒绝策略异常
            for (int i = 0; i < 9; i++) {
                //不用new thread,而是从线程池取
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"--");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完要关闭
            threadPool.shutdown();
        }
    }
}
---------------结果---------------
pool-1-thread-1--
pool-1-thread-4--
pool-1-thread-3--
pool-1-thread-2--
pool-1-thread-3--
pool-1-thread-4--
pool-1-thread-5--
pool-1-thread-1--

小结与扩展

最大线程到底该如何定义:(用于调优)
1.CPU密集型,几核,就是几,可以保持CPU的效率最高

获取cpu核心数:
Runtime.getRuntime().availableProcessors();

2.IO密集型
判断,你的程序中,十分耗用资源的IO线程有多少个
大约创建两倍IO程序的线程数

import java.util.concurrent.*;

public class Demo02 {
    public static void main(String[] args) {
        //自定义线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(),//获取核心数
                3, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                //第一种拒绝策略
                //new ThreadPoolExecutor.AbortPolicy());//如果超出8个线程,不处理,线程就会报错,抛出异常
                //第二种拒绝策略
                //new ThreadPoolExecutor.CallerRunsPolicy()
                //第三种拒绝策略
                new ThreadPoolExecutor.DiscardPolicy()); //队列满了,不会抛出异常
                //第四种拒绝策略
                //new ThreadPoolExecutor.DiscardOldestPolicy()); //试探最早的线程是否结束,如果结束就跟进,没结束不处理,不会抛出异常
        try {
            //最大承载 = Deque + max
            //超出最大承载就会抛出:RejectedExecutionException异常,被拒绝策略异常
            for (int i = 0; i < 9; i++) {
                //不用new thread,而是从线程池取
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"--");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完要关闭
            threadPool.shutdown();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值