Java线程池ThreadPoolExecutor

1.线程池的基本使用

2.线程池的创建

3.volatile关键字的用法

4.多线程操作共享数据(多线程重点)

4.1数据原子性--举个反例

4.2 解决方案 自旋锁+CAS算法

4.3 乐观锁和悲观锁

4.4 HashMap线程不安全

4.5 ConcurrentHashMap

4.6 CountDownLatch工具类

4.7 Semaphore 线程控制类


1.线程池的基本使用

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

public class MyPool {
    public static void main(String[] args) {
        //这是一个线程创建工具,他会判断线程池子里面是否有空闲的线程,有就用空闲的线程
        //没有则创建,这边能创建最大的线程就是Int的最大值,这个线程池某种意义上线程数量
        //无限制,这边注意一下 ExecutorService这个是一个接口
        ExecutorService executorService = Executors.newCachedThreadPool();
        Executors.newFixedThreadPool(10);//这种创建方式是创建一个线程上限的池子
        //这边的入参是Runabled接口,所以可以lamda
        executorService.submit(()->{
            System.out.println(Thread.currentThread().getName()+"吃饭");
        });

        executorService.submit(()->{
            System.out.println(Thread.currentThread().getName()+"吃饭");
        });
        executorService.submit(()->{
            System.out.println(Thread.currentThread().getName()+"吃饭");
        });
        //关闭线程池
        executorService.shutdown();
    }
}

2.线程池的创建

import java.util.concurrent.*;

public class MyPoolThread {
    public static void main(String[] args) {
        int corePoolSize = 5;//核心线程数量,创建就不会被销毁
        int maximumPoolSize =10;//全部的数量
        long keepAliveTime=10;//非核心线程多场失效
        TimeUnit unit = TimeUnit.SECONDS;//单位
        //这边的队列是如果我所有的线程都有事,那么再来一个新的任务就到队列等待线程释放
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1);
        //如果队列也满了,那么就开始拒绝。
        //拒绝策略一共有四种
        //ThreadPoolExecutor.AbortPolicy 拒绝并跑出异常
        //ThreadPoolExecutor.DiscardPolicy 拒绝不抛出异常
        //ThreadPoolExecutor.CallerRunsPolicy  抛弃队列里面等待时间最长的任务
        //ThreadPoolExecutor.DiscardOldestPolicy 不用线程池,直接给其他线程处理
        RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(corePoolSize,
                        maximumPoolSize,
                        keepAliveTime,
                        unit,
                        workQueue,
                        Executors.defaultThreadFactory(),
                        handler);
        threadPoolExecutor.execute(()->{
            System.out.println("运行任务");
        });
    }
}

3.volatile关键字的用法

public class MyPoolVolatile {
    //有10个汉堡
    private static volatile int HanBaoBao = 10;
    //下面要做一个事情,就是我有两个线程一个叫老7要去偷吃老八的汉堡,
    // 但是老八每天都会数一下,发现了就会报警!
    //这边的代码会陷入死循环
    //有两个解决方法
    //第一种就是    private static volatile int HanBaoBao = 10;
    //第二种就是加把锁
    //这边的机制其中一个线程如果改了共同的变量,
    // 那么就提醒使用这个变量的线程,重新拿一下值
    public static void main(String[] args) {
        //这是老八
        new Thread(()->{
        while(true){
            if(HanBaoBao!=10){
                System.out.println("嗨嗨害!报警!");
                break;
            }else{

            }
        }
        }).start();
        //这边是小偷我偷汉堡
        new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            HanBaoBao = 7;
        }).start();
    }
}

4.多线程操作共享数据(多线程重点)

这边呢也是我在工作中的时候呢遇到一个比较重要的问题,我多线程去操作某一集合对象,如果仅仅是查询其实也无所谓,但是设计到更改,那么这个共享数据也能就会产生问题,那么有问题就需要解决!

4.1数据原子性--举个反例

这边用volatile 关键字也是不行的,同步代码块是可以,但是效率较慢

public class ThreadAddNum {
    //我现在有个场景,如果我有一百个线程去操作num,每个线程我加100次
    //那么最后的结果是不是num就是10000?这边的结果就不是?如果是10000你多试几次
    //会发现结果是飘忽不定的
    //这就出现了问题
    private static int num = 0;
    public static void main(String[] args) {
        for(int i=0;i<100;i++){
             new Thread(()->{
                 for(int a=0;a<100;a++){
                     num++;
                     System.out.println(num);
                 }
             }).start();
        }
    }

}

4.2 解决方案 自旋锁+CAS算法

CAS算法就是在每次去操作共享数据A的时候事先会把原数据进行备份B,然后我更改再创建一个新的值B2,不动这个备份数据B,那么最后需要给这个共享数据新值的时候我先看一下,目前的这个值A等于不等于我最开始的数据备份值B。如果是那,么我在把B2这个修改过的值给A。

import java.util.concurrent.atomic.AtomicInteger;

public class MyAomic {

//    private static int num = 0;
    private static AtomicInteger num = new AtomicInteger(0);
    public static void main(String[] args) {
        //这边有很多类Atomic包里面的类我这边只用到了
        //integer所以就举一下这个例子
        AtomicInteger atomicInteger =  new AtomicInteger(10);
        //下面都是一些操作这个对像的方法,和多线程并没有关系
        System.out.println(atomicInteger.get());//获取这个对象里面的值
        System.out.println(atomicInteger.getAndIncrement());//自增之前的值
        System.out.println(atomicInteger.incrementAndGet());//自增之后的值,看名字都是有说法的规律自己找
        System.out.println(atomicInteger.getAndAdd(88));
        System.out.println(atomicInteger.getAndSet(0));
        for(int i=0;i<100;i++){
            new Thread(()->{
                for(int a=0;a<100;a++){
                    num.incrementAndGet();
                    System.out.println(num.get());
                }
            }).start();
        }

    }
}

4.3 乐观锁和悲观锁

悲观锁就是synchronized代码块 ,我默认就认为别人会抢我的老婆。我每次干活我就先锁门,防止别人抢我老婆。

乐观锁就是我默认不会抢我老婆,但是我每天回家时候我检查一下,看看是不是原来的形状。

4.4 HashMap线程不安全

HashMap不安全,可以替换成HashTable ,但是效率很低,那么为了效率就会有专门解决这个问题的类对象

import java.util.HashMap;

public class MyHash {
    private static HashMap<String,String> map =new HashMap<>();

    public static void main(String[] args) throws InterruptedException {
        new  Thread(()->{
            for (int i = 0; i < 50; i++) {
                map.put(i+"",i+"");
            }
        }).start();

        new  Thread(()->{
            for (int i = 50; i < 100; i++) {
                map.put(i+"",i+"");
            }
        }).start();

        new  Thread(()->{
            for (int i = 100; i < 150; i++) {
                map.put(i+"",i+"");
            }
        }).start();
        Thread.sleep(1000);
        for (int i = 0;i<200;i++)
            System.out.println(map.get(i+""));
    }
}

4.5 ConcurrentHashMap

这个一般在多线程的场景下使用,线程安全和效率高,这边有兴趣的同学可以看一下原理,7版本和8版本原理有所不同。这边大概提一下,7版本是用的二次hash原理,8版本用了CAS算法

4.6 CountDownLatch工具类

这个类是控制线程的执行顺序的,之前的权重虽然可以控制,但是无法百分之百。可以用这个类绝对的控制线程的执行顺序

import java.util.concurrent.CountDownLatch;

public class MyCountLatch {
    //这边是控制线程的执行顺序,这边传入的数字就是唤醒等待的线程
    //这边的意思就是当这个数字为0的时候就会去执行countDownLatch.await();的线程
    private static CountDownLatch countDownLatch = new CountDownLatch(2);
    public static void main(String[] args) {
        new Thread(()->{
            try {
                //等待
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("嗨嗨害!");
        }).start();

        new Thread(()->{
            try {
                //等待
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("嗨嗨害!2");
        }).start();

        new Thread(()->{
            try {
                Thread.sleep(100);
                System.out.println("老八秘制小汉堡!1");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(()->{
            try {
                Thread.sleep(200);
                System.out.println("老八秘制小汉堡!2");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

4.7 Semaphore 线程控制类

控制一次能有几个线程可以执行

import java.util.concurrent.Semaphore;

public class MySemaphore {
    //最多允许2个线程进行操作
    private static Semaphore mySemaphore = new Semaphore(2);
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                try {
                    mySemaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("我又进来啦!打我打我啊!");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("我又出来啦!");
                mySemaphore.release();
            }).start();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值