• Juc(上)


    1、什么是JUC?

    java.util 工具包、包、分类

    业务:普通的线程代码 Thread

    Runnable 没有返回值、效率相比于Callable相对较低,所以开发中大多使用Callable

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

    •   cpu单核,模拟出来多条线程,天下武功,唯快不破,快速交替

    并行(多个人一起行走)

    •   cpu多核,多个线程可以同时执行; 要提高性能可以用线程池
    public class Test1 {
        public static void main(String[] args) {
            // 获取cpu的核数
            System.out.println(Runtime.getRuntime().availableProcessors());
        }
    }

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

    线程的状态:(源码中)

    wait和sleep的区别

    1、来自不同的类

    • wait => Object
    • sleep => Thread

    2、是否释放锁

    • wait不释放锁
    • sleep释放锁

    3、使用的范围不同

    • wait必须在同步代码块中
    • sleep可以在任何地方睡

    4、是否需要捕获异常

    • wait不需要捕获异常
    • sleep必须捕获异常(因为可能会发生超时等待的状况)

    三、Lock锁(重点)

     

     ReentrantLock的底层默认是非公平锁:(假如一个3s执行完,一个3小时执行完,如果用公平锁,3s的要等3小时)

     公平锁:不能插队

    非公平锁:可以插队

     传统的锁Synchronized:

    // 基本的卖票例子
    /*
    * 真正的多线程开发,公司中的开发,要降低耦合性
    * 线程就是一个单独的资源类,没有任何附属的操作
    * 1.属性 2、方法
    * */
    public class SaleTicketDemo01 {
        public static void main(String[] args) {
            // 并发:多线程操作同一个资源类
            Ticket ticket = new Ticket();  // 资源类
    
            // @FunctionalInterface 函数式接口。
            /*
            匿名内部类,写起来比较繁琐,直接用lambda表达式 (参数)->{代码}  ()是从方法体开始的
            new Thread(new Runnable() {
                @Override
                public void run() {
    
                }
            }).start();*/
            new Thread(()->{   // 多线程
                for (int i = 1; i < 20; i++) {  // 操作:把资源类丢入线程
                    ticket.sale();
                }
            },"A").start();
            new Thread(()->{
                for (int i = 1; i < 20; i++) {
                    ticket.sale();
                }
            },"B").start();
            new Thread(()->{
                for (int i = 1; i < 20; i++) {
                    ticket.sale();
                }
            },"C").start();
    
    
        }
    }
    
    // 资源类 用oop思想
      class  Ticket {
        // 属性方法
        private int number = 30;
        // 卖票的方式
        // synchronized本质:队列,锁
        public synchronized void sale() {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第" + (number--) + "张票" + "还剩" + number);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }

    lock锁:

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    // 基本的卖票例子
    /*
     * 真正的多线程开发,公司中的开发,要降低耦合性
     * 线程就是一个单独的资源类,没有任何附属的操作
     * 1.属性 2、方法
     * */
    public class SaleTicketDemo02 {
        public static void main(String[] args) {
            // 并发:多线程操作同一个资源类
            Ticket ticket = new Ticket();  // 资源类
            new Thread(()->{for (int i = 1; i < 20; i++) ticket.sale(); },"A").start();
            new Thread(()->{for (int i = 1; i < 20; i++) ticket.sale(); },"B").start();
            new Thread(()->{for (int i = 1; i < 20; i++) ticket.sale(); },"C").start();
    
        }
    }
    
    // Lock三部曲
    /*
    1:new ReentrantLock();
    2:加锁lock.lock();
    3:解锁lock.unlock();
    */
    
    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);
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             } finally {
                 lock.unlock();
             }
    
    
    
        }
    }

    思考:lock锁和synchronized有什么区别?(记住4-5个)(想象成自动挡和手动挡)

    1:synchronized是一个关键字,而lock是一个类

    2:synchronized适合少量的代码,而lock适合大量的代码块

    3:synchronized是自动的加锁解锁,而lock需要手动加锁解锁

    4:synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等) lock不一定傻傻的等下去,它会尝试获取锁trylock()

    5:synchronized无法获取锁的状态,而lock可以判断是否获取了锁

    6:synchronized 可重入锁,不可中断的,非公平   lock 可重入锁,可以判断锁,非公平(可以自己设置)

    public ReentrantLock(boolean fair) {
            this.sync = (ReentrantLock.Sync)(fair ? new ReentrantLock.FairSync() : new ReentrantLock.NonfairSync());
        }

    传统的生产者和消费者问题,虚假唤醒

    public class A {
        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();
    
            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();
    
        }
    }
    // 生产者消费者口诀
    // 判断等待,业务,通知
    class Data{
        private int number = 0;
    
        // +1
        public synchronized void increment() throws InterruptedException {
           if (number != 0) {
                // 等待
                this.wait();
    
            }
            Thread.sleep(100);
            number++; // 业务
            System.out.println(Thread.currentThread().getName() + " => " + number);
            // 通知其它线程我+1加完了
            this.notifyAll();
    
        }
    
    
        // -1
        public synchronized void decrement() throws InterruptedException {
           if (number == 0) {
                // 等待
                this.wait();
            }
            Thread.sleep(100);
            number--;
            System.out.println(Thread.currentThread().getName() + " => " + number);
            // 通知其它线程我-1加完了
            this.notifyAll();
        }
    }

    两个线程的时候还正常,四个进程之后就乱套了

     问题解决:

    // 生产者消费者口诀
    // 判断等待,业务,通知
    class Data{
        private int number = 0;
    
        // +1
        public synchronized void increment() throws InterruptedException {
           while (number != 0) {
                // 等待
                this.wait();
    
            }
            Thread.sleep(100);
            number++; // 业务
            System.out.println(Thread.currentThread().getName() + " => " + number);
            // 通知其它线程我+1加完了
            this.notifyAll();
    
        }
    
    
        // -1
        public synchronized void decrement() throws InterruptedException {
          while (number == 0) {
                // 等待
                this.wait();
            }
            Thread.sleep(100);
            number--;
            System.out.println(Thread.currentThread().getName() + " => " + number);
            // 通知其它线程我-1加完了
            this.notifyAll();
        }
    }

     

  • 相关阅读:
    南阳97
    南阳96
    南阳94
    南阳77
    南阳75
    南阳74
    南阳65
    一般图匹配
    466E
    hdu5057 分块处理,当数值大于数据范围时树状数组 真是巧 将大数据分为小数据来处理
  • 原文地址:https://www.cnblogs.com/YXBLOGXYY/p/14856863.html
Copyright © 2020-2023  润新知