多线程知识整理

线程使用方式

4种方式模拟多线程,继承Thread、实现Runable接口、实现Callable接口、使用线程池。

class mytest4 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <1000 ; i++) {
            System.out.println("线程名字:"+Thread.currentThread().getName()+":"+i);
        }
    }
    public static void main(String[] args) {
        new mytest4().start();
        new mytest4().start();
    }
}
class b implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <1000 ; i++) {
            System.out.println("线程名字:"+Thread.currentThread().getName()+":"+i);
        }
    }
    public static void main(String[] args) {
        new Thread(new b(),"线程一").start();
        new Thread(new b(),"线程二").start();
    }
}
class c implements Callable{
    public String arg;

    public c(String arg) {
        this.arg = arg;
    }
    @Override
    public Object call() throws Exception {
        for (int i = 0; i <1000 ; i++) {
            System.out.println("线程名字:"+Thread.currentThread().getName()+":"+i+"参数"+arg);

        }
        return "自定义返回值";
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> c = new c("juno");
        FutureTask<String> futureTask=new FutureTask<>(c);
        new Thread(futureTask).start();
        System.out.println("获取多线程的返回值:"+futureTask.get());
    }
    public static void main(String[] args) {
        //带缓存的线程池
        Executors.newCachedThreadPool();
        //特定长度的线程池
        Executors.newFixedThreadPool(5);
        //有执行周期的线程池
        Executors.newScheduledThreadPool(1);
        //单个线程的线程池
        Executors.newSingleThreadExecutor();
    }
}

线程安全问题

保证原子性,可见性,指令不重排即可保证线程安全。

原子性: 一系列代码不会被打断。
可见性:线程1对数据的修改,线程2实时可见。
指令重排:单线程下代码顺序在不影响结果下代码会随机执行其优化作用,在多线程环境下会引起数据不一致。

关键字 volatile 保证可见性,禁止指令重排,不保证原子性。
关键字 synchronized 保证原子性,保证可见性,禁止指令重排。

参考线程交互内存模型:
线程间数据交换的方式
Q1:i++;操作在多线程的环境下,数据不一致,如何一致?
A1:采用原子整型(AtomicInteger)做i++操作。
Q2:原子整型是如何保证多线程环境下数据安全的?
A2:利用compare and swap 原理保证。
Q3:compare and swap缺点
A3:1.底层会一直重复判断参数是否与期望值一致,性能开支大。
2.只能保证一个共享变量的原子性操作。
3.ABA问题。

线程池原理及使用

线程池=核心处理线程数+最大处理线程数+阻塞队列+拒绝策略

线程池优势

线程的复用减少资源消耗极端情况下防止Cpu过载,不需要管理具体线程交由线程池管理。

线程池底层运行原理

线程池最长的工作流程: 核心线程数已满>任务进入阻塞队列>阻塞队列已满>开启最大线程池>阻塞队列+最大线程数已满>拒绝策略

在这里插入图片描述
线程池内部处理图:
在这里插入图片描述

阻塞队列原理

原理:生产者消费者模式。
优势:通过无锁即能控制线程的顺序执行。
技术实现:通过阻塞队列BlockingQueue实现。
传统生产者消费者模式:

public class four  {
    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    public Integer num=0;
    public void add(){
        lock.lock();
        try {
            while(num!=0){
                    condition.await();
                    //System.out.println("生产完毕!!等待消费"+Thread.currentThread().getName());
            }
            num++;
            System.out.println("开始生产!!线程是:"+Thread.currentThread().getName());
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void sub(){
        lock.lock();
        try {
            while(num==0){
                    condition.await();
                    //System.out.println("消费完毕!!等待生产"+Thread.currentThread().getName());
            }
            num--;
            System.out.println("开始消费!!线程是:"+Thread.currentThread().getName());
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
            four four = new four();
        new Thread(()->{
            for (int i = 0; i <5 ; i++) {
                four.add();
            }
        },"AAA").start();

        new Thread(()->{
            for (int i = 0; i <5 ; i++) {
                four.sub();
            }
        },"BBB").start();
    }
}

无锁版:

public class five {
    private  volatile Boolean Flag=true;
    private  BlockingQueue<String> blockingQueue=null;
    private AtomicInteger atomicInteger = new AtomicInteger(0);
    
    public void add()  {
        try {
            Boolean offer = false;
            while (Flag) {
                String value = atomicInteger.incrementAndGet() + "";
                synchronized (this) {
                    offer = blockingQueue.offer(value, 2, TimeUnit.SECONDS);
                    System.out.println();
                    System.out.println();
                    System.out.println();
                    if (offer) {
                        System.out.println("线程" + Thread.currentThread().getName() + "生产产品(编号" + value + ")成功");
                    } else {
                        System.out.println("线程" + Thread.currentThread().getName() + "生产失败");
                    }
                }
                    TimeUnit.SECONDS.sleep(1);
                }
                System.out.println("收到指令停止生产");
            } catch(Exception e){
                e.printStackTrace();
            }
    }
    
    public void sub(){
        try {
            String poll = null;
            while(Flag){
               poll = blockingQueue.poll(2, TimeUnit.SECONDS);
                if(poll!=null){
                    System.out.println("线程"+Thread.currentThread().getName()+"消费产品(编号"+poll+")成功");
                }else {
                    System.out.println("线程"+Thread.currentThread().getName()+"消费失败");
                    Flag = false;
                    return;
                }
                TimeUnit.SECONDS.sleep(1);
            }
            System.out.println("收到指令停止消费");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void stop(){
        System.out.println("要求停止所有动作");
        Flag=false;
    }
    public five(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }
    public static void main(String[] args) throws Exception{
        five five = new five(new SynchronousQueue<>());
        new Thread(()->{
                five.add();
        },"AAA").start();
        new Thread(()->{
                five.sub();
        },"BBB").start();
        TimeUnit.SECONDS.sleep(5);
        five.stop();
    }
}
最大线程数的合理配置

cpu密集型:cpu数+1
io密集型:cpu数/(1-阻塞系数) 阻塞系数=0.8~0.9

各种锁机制

常用锁类型:公平锁/非公平锁;可重入锁(递归锁);自旋锁;独占锁/共享锁

自旋锁实例:

//模拟自旋锁
//利用compare and swap(比较并交换)机制实现自旋锁
public class spinLock {
    private AtomicReference<Thread> reference = new AtomicReference<>();

    public  void mylock(){
        Thread thread = Thread.currentThread();
        System.out.println("进入加锁阶段");

        while(!reference.compareAndSet(null,thread))
        {
            //System.out.println("尝试获取锁");
        }
        System.out.println("加锁完成阶段");
    }
    public  void unlock(){
        Thread thread = Thread.currentThread();
        reference.compareAndSet(thread,null);
        System.out.println("完成解锁");
    }
    public static void main(String[] args) {
        spinLock lock = new spinLock();
           new Thread(()->{
               try {
                   lock.mylock();
                   System.out.println("进入5秒等待时间");
                   Thread.sleep(5000);
                   System.out.println("处理业务操作");
                   lock.unlock();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }."线程1").start();

          new Thread(()->{
              lock.mylock();
              System.out.println("处理业务操作");
              lock.unlock();
          },"线程2").start();
    }
    //运行结果:
    进入加锁阶段
	加锁完成阶段
	进入5秒等待时间
	进入加锁阶段
	处理业务操作
	完成解锁
	加锁完成阶段
	处理业务操作
	完成解锁
}

独占锁/共享锁实例:

//模拟读写锁
//读-读 共享锁
//读-写 独占锁
//写-写 独占锁
public class ReadWriteLock {
    HashMap<String,Object> myMap = new HashMap<>();
    ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
    private void put(String s,Object obj){
        myLock.writeLock().lock();
        System.out.println("当前写线程:"+Thread.currentThread().getName());
        myMap.put(s,obj);
        System.out.println("数据写入成功!当前写线程:"+Thread.currentThread().getName());
        myLock.writeLock().unlock();
    }
    private void get(String s){
        myLock.readLock().lock();
        Object o = myMap.get(s);
        System.out.println("获取到的数据:"+o);
        myLock.readLock().unlock();
    }
    public static void main(String[] args) {
        ReadWriteLock readWriteLock = new ReadWriteLock();
        for (int i = 0; i <10 ; i++) {
            int j = i;
            new Thread(()->{
                readWriteLock.put(j+"",j);
                readWriteLock.get(j+"");
            },"线程"+j).start();
        }
    }
    //运行结果:
    当前写线程:线程0
	数据写入成功!当前写线程:线程0
	当前写线程:线程1
	数据写入成功!当前写线程:线程1
	获取到的数据:0
	获取到的数据:1
	当前写线程:线程2
	数据写入成功!当前写线程:线程2
	当前写线程:线程3
	数据写入成功!当前写线程:线程3
	当前写线程:线程4
	数据写入成功!当前写线程:线程4
	当前写线程:线程5
	数据写入成功!当前写线程:线程5
	当前写线程:线程6
	数据写入成功!当前写线程:线程6
	当前写线程:线程7
	数据写入成功!当前写线程:线程7
	当前写线程:线程8
	数据写入成功!当前写线程:线程8
	当前写线程:线程9
	数据写入成功!当前写线程:线程9
	获取到的数据:9
	获取到的数据:3
	获取到的数据:5
	获取到的数据:2
	获取到的数据:8
	获取到的数据:7
	获取到的数据:6
	获取到的数据:4
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值