JUC并发编程

1. 线程和进程
  • 进程: 一个程序,QQ.exe Music.exe 程序的集合; 一个进程往往可以包含多个线程,至少包含一个。

  • Java默认有几个线程: 2 个(mianGC)。

  • 线程:开了一个进程 Typora,写字,自动保存(线程负责的)

  • 创建线程(对于Java而言):ThreadRunnableCallable

  • Java真的可以开启线程吗? 不可以开启线程。

    public synchronized void start() {
        if (threadStatus != 0)throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
    // 本地方法,底层的C++ ,Java 无法直接操作硬件 
    private native void start0();
    
  • 并发(多线程操作同一个资源): CPU 一核 ,模拟出来多条线程,快速交替 。

  • 并行(多个人一起行走): CPU 多核 ,多个线程可以同时执行; 线程池。

    public static void main(String[] args) {
        //获取cpu的核数
        //CPU密集型,IO密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
    
  • 线程有几个状态。

    public enum State {
        //尚未启动的线程的线程状态
        NEW,
        //可运行线程的线程状态
        RUNNABLE,
        //等待监视器锁的阻塞线程的线程状态
        BLOCKED,
    	//等待线程的线程状态
        WAITING,
    	//具有指定等待时间的等待线程的线程状态
        TIMED_WAITING,
    	//终止线程的线程状态
        TERMINATED;
    }
    
  • wait / sleep 区别:

    • 来自不同的类:wait => Object ,sleep => Thread
    • 锁的释放: wait会释放锁,sleep 不会释放锁
    • 使用的范围不同:wait必须在同步代码块中,sleep可以在任何地方
2. Lock锁
  • 传统 Synchronized

    public static void main(String[] args) {
        // 并发:多线程操作同一个资源类, 把资源类丢入线程
        Ticket ticket = new Ticket();
        //@FunctionalInterface 函数式接口,jdk1.8 lambda表达式 (参数)->{ 代码 }
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.sale();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.sale();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.sale();
            }
        }, "C").start();
    }
    //资源类OOP
    static class Ticket {
        //属性、方法
        private int number = 30;
        //卖票的方式
        //synchronized 本质: 队列,锁
        public synchronized void sale() {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余:" + number);
            }
        }
    }
    //结果
    A卖出了30,剩余:29
    A卖出了29,剩余:28
    ...
    A卖出了3,剩余:2
    A卖出了2,剩余:1
    A卖出了1,剩余:0
    
  • Lock 接口:

    public static void main(String[] args) {
        // 并发:多线程操作同一个资源类, 把资源类丢入线程
        Ticket2 ticket = new Ticket2();
        // @FunctionalInterface 函数式接口,jdk1.8 lambda表达式 (参数)->{ 代码 }
        new Thread(() -> {
            for (int i = 1; i < 40; i++) ticket.sale();
        }, "A").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) ticket.sale();
        }, "B").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) ticket.sale();
        }, "C").start();
    
    }
    
    // Lock三部曲
    // 1、new ReentrantLock();
    // 2、lock.lock(); //加锁
    // 3、finally=> lock.unlock(); //解锁
    static class Ticket2 {
        //属性、方法
        private int number = 30;
        Lock lock = new ReentrantLock();
    
        public void sale() {
            lock.lock(); //加锁
            try {
                //业务代码
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余:" + number);
                }
            } catch (
                    Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock(); // 解锁
            }
        }
    }
    //结果
    A卖出了30,剩余:29
    A卖出了29,剩余:28
    ...
    A卖出了3,剩余:2
    A卖出了2,剩余:1
    A卖出了1,剩余:0
    
  • SynchronizedLock区别:

    • Synchronized内置的Java关键字, Lock 是一个Java类。
    • Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁。
    • Synchronized会自动释放锁,lock必须要手动释放锁!如果不释放锁,死锁。
    • Synchronized 线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去。
    • Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以自己设置)。
    • Synchronized适合锁少量的代码同步问题,Lock 适合锁大量的同步代码。
3. 生产者和消费者问题
  • 生产者和消费者问题Synchronized版:

    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.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
    }
    // 判断等待,业务,通知
    static class Data { // 数字 资源类
        private int number = 0;
        public synchronized void increment() throws InterruptedException {
            if (number != 0) {  //0
                // 等待
                this.wait();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我+1完毕了
            this.notifyAll();
        }
        public synchronized void decrement() throws InterruptedException {
            if (number == 0) { // 1
                // 等待
                this.wait();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我-1完毕了
            this.notifyAll();
        }
    }
    //结果
    A=>1
    B=>0
    A=>1
    B=>0
    A=>1
    B=>0
    ...
    
  • 问题存在,A B C D4个线程! 虚假唤醒:
    在这里插入图片描述

  • JUC版的生产者和消费者问题:

    public static void main(String[] args) {
        Data2 data = new Data2();
        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.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();
    }
    // 判断等待,业务,通知
    static class Data2 { // 数字 资源类
        private int number = 0;
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        //condition.await(); //等待
        //condition.signalAll(); //唤醒全部
        public void increment() throws InterruptedException {
            lock.lock();
            try {
                //业务代码
                while (number != 0) { //0
                    //等待
                    condition.await();
                }
                number++;
                System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我+1完毕了
                condition.signalAll();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public synchronized void decrement() throws InterruptedException {
            lock.lock();
            try {
                while (number == 0) { // 1
                    // 等待
                    condition.await();
                }
                number--;
                System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我-1完毕了
                condition.signalAll();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
    }
    //结果
    A=>1
    B=>0
    A=>1
    B=>0
    A=>1
    B=>0
    ...
    C=>1
    D=>0
    C=>1
    D=>0
    C=>1
    D=>0
    ...
    
  • Condition 精准的通知和唤醒线程:

    public static void main(String[] args) {
        Data3 data = new Data3();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printA();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printB();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                data.printC();
            }
        }, "C").start();
    }
    static class Data3 { //资源类 Lock
        private Lock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
        private int number = 1; // 1A 2B 3C
        public void printA() {
            lock.lock();
            try {
                //业务,判断-> 执行-> 通知
                while (number != 1) {
                    //等待
                    condition1.await();
                }
                System.out.println(Thread.currentThread().getName() + "=>AAAAAAA"); // 唤醒,唤醒指定的人,B
                number = 2;
                condition2.signal();
            } catch (
                    Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void printB() {
            lock.lock();
            try {
                //业务,判断-> 执行-> 通知
                while (number != 2) {
                    condition2.await();
                }
                System.out.println(Thread.currentThread().getName() + "=>BBBBBBBBB"); // 唤醒,唤醒指定的人,c
                number = 3;
                condition3.signal();
            } catch (
                    Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void printC() {
            lock.lock();
            try {
                //业务,判断-> 执行-> 通知 // 业务,判断-> 执行-> 通知
                while (number != 3) {
                    condition3.await();
                }
                System.out.println(Thread.currentThread().getName() + "=>CCCCCCC"); // 唤醒,唤醒指定的人,c
                number = 1;
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    //结果
    A=>AAAAAAA
    B=>BBBBBBBBB
    C=>CCCCCCC
    A=>AAAAAAA
    B=>BBBBBBBBB
    C=>CCCCCCC
    A=>AAAAAAA
    B=>BBBBBBBBB
    C=>CCCCCCC
    ...
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值