• 二:JAVA通知唤醒机制,Lock替换synchronize


    上一篇生产者消费者模型中我们使用的是synchronize锁,选择我们需要换成Lock锁

      Lock和synchronize的区别(synchronize的是随机抢到时间片,Lock可以按照顺序抢时间片精确让某个线程signal:condition配多把钥匙)

       补充:notity并不会立即释放锁,需要等到执行notify()方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁Lock的让出时间片的方式也是一样的

    1. Lock是一个接口,而synchronized是关键字。
    2. synchronized会自动释放锁,而Lock必须手动释放锁。
    3. Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。
    4. 通过Lock可以知道线程有没有拿到锁,而synchronized不能。
    5. Lock能提高多个线程读操作的效率。
    6. synchronized能锁住类、方法和代码块,而Lock是块范围内的
    7. synchronize的通知唤醒用的是wait()和notify,Lock使用的是Condition里面的await() 和signal();

    把synchronize的锁换成Lock(并发中的判断最好用while而不要用if为了防止线程的虚假唤醒)

    任务:生产一个抢一个一直循环

    package work;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    class MaiPiao{
        private int piao=0;
        public int bbbb=30;
        Lock lock = new ReentrantLock();
        public synchronized void incry() throws Exception {
            while (piao != 0) this.wait();
            piao ++;
            System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao);
            Thread.sleep(300);
            this.notifyAll();}
        
        
        public synchronized void decry() throws Exception {
            while (piao == 0 ) this.wait();
            Thread.sleep(500);
            piao--;
            System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao);
            this.notifyAll();}}
    
    
    public class Shangguigu {
        public static void main(String[] args) throws Exception {
            MaiPiao maiPiao = new MaiPiao();
            new Thread(()->{for (int i = 0; i < 10; i++) {
                try {
                    maiPiao.incry();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }}},"A").start();
            new Thread(()->{for (int i = 0; i < 10; i++) {
                try {
                    maiPiao.decry();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }}},"B").start();}}
    synchronize的通知唤醒机制
    package work;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class MaiPiao{
        private int piao=0;
    
        Lock lock = new ReentrantLock();
        Condition condition    = lock.newCondition();
        public void incry() throws Exception {
            lock.lock();
            try {
                while (piao != 0) condition.await();
                piao ++;
                System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao);
                Thread.sleep(300);
                condition.signalAll();
            }catch (Exception e) {
                // TODO: handle exception
            }finally {
                lock.unlock();
                }
        }
        public void decry() throws Exception {
            lock.lock();
            try {
                while (piao == 0 ) condition.await();
                Thread.sleep(500);
                piao--;
                System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao);
                condition.signalAll();
            }catch (Exception e) {
                // TODO: handle exception
            }finally {
                lock.unlock();
            }}
    
    }
    public class Shangguigu {
        public static void main(String[] args) throws Exception {
            MaiPiao maiPiao = new MaiPiao();
            new Thread(()->{for (int i = 0; i < 10; i++) {
                try {
                    maiPiao.incry();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }}},"A").start();
            new Thread(()->{for (int i = 0; i < 10; i++) {
                try {
                    maiPiao.decry();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }}},"B").start();
            }
        }
    Lock的唤醒机制

    任务:线程A打印五次,线程B打印10次,线程C打印15次(可以一个lock配多个condition来指定signal:awite和signal的相互搭配使用的)

    package work;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class MaiPiao{
        // 由于要按照顺序ABC的执行    判断  操作   
        // 首先要有执行的内容
        // 其次多线程打印而且要按照顺序,所以要做一个顺序的标志位
        // 由于是多线程首先要加锁
        // 
        private int flag = 1; //从1开始
        private Lock lock = new ReentrantLock();
        
        // 创建三个condition
        Condition work1 = lock.newCondition();
        Condition work2 = lock.newCondition();
        Condition work3 = lock.newCondition();
        
        public void work1() throws Exception {
    
            lock.lock();
            while (flag !=1) {
                work1.await();
            }
            try {
                System.out.println(Thread.currentThread().getName()+" 正在打印 5 ");
                flag=2;
                work2.signal();
            }catch (Exception e) {
                // TODO: handle exception
            }finally {
                lock.unlock();}}
        
        public void work2() throws Exception {
    
            lock.lock();
            while (flag !=2) {
                work2.await();
            }
            try {
                System.out.println(Thread.currentThread().getName()+" 正在打印 10 ");
                flag=3;
                work3.signal();
            }catch (Exception e) {
                // TODO: handle exception
            }finally {
                lock.unlock();}}
        
        public void work3() throws Exception {
    
            lock.lock();
            while (flag !=3) {
                work3.await();
            }
            try {
                System.out.println(Thread.currentThread().getName()+" 正在打印 15 ");
                flag=1;
                work1.signal();
            }catch (Exception e) {
                // TODO: handle exception
            }finally {
                lock.unlock();}}
    }
    
    
    public class Shangguigu {
        public static void main(String[] args) throws Exception {
            MaiPiao maiPiao = new MaiPiao();
            
            new Thread(() -> {
                try {
                    for (int i = 0; i < 3; i++) maiPiao.work1();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }, "A").start();
            
            new Thread(() -> {
                try {
                    for (int i = 0; i < 3; i++) maiPiao.work2();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }, "B").start();
            
            new Thread(() -> {
                try {
                    for (int i = 0; i < 3; i++) maiPiao.work3();   //循环三次
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }, "C").start();
        }
    }
    Lock定向让出时间片

    # 四个创建线程的方法要记得

  • 相关阅读:
    k8s 重要概念
    k8s 核心功能
    5 秒创建 k8s 集群
    学习 Kubernetes 的 Why 和 How
    Yeelink初步体验
    为Qemu aarch32添加BeautifulSoup4模块
    实现Qemu aarch32虚拟开发板ping www.baidu.com
    利用/proc/pid/pagemap将虚拟地址转换为物理地址
    加快Qemu Aarch32虚拟开发板的启动速度
    为Qemu aarch32开发板添加sd卡
  • 原文地址:https://www.cnblogs.com/BookMiki/p/14099424.html
走看看 - 开发者的网上家园