zoukankan      html  css  js  c++  java
  • java线程锁

    出处;https://www.liaoxuefeng.com/wiki/1252599548343744/1306581033549858
    

    java线程锁是重入锁:一个线程可以重复获取锁
    if (lock.tryLock(1, TimeUnit.SECONDS)) {
        try {
            ...
        } finally {
            lock.unlock();
        }
    }

    使用private final Lock lock = new ReentrantLock();
    先去获取锁,然后再去铺获代码块

    、最多等待1秒。如果1秒后仍未获取到锁,tryLock()返回false,不会无限等待下去。

    所以,使用ReentrantLock比直接使用synchronized更安全,线程在tryLock()失败的时候不会导致死锁
    
    package com.example.demo.config;
    
    public class Thread1 extends Thread{
        public void run() {
            System.out.println("Thread-1: try get lock A...");
            synchronized (Demo.lockA) { //给A加锁
                System.out.println("Thread-1: lock A got.");
                Demo.sleep1s();
                System.out.println("Thread-1: try get lock B...");
                synchronized (Demo.lockB) {//获取B锁
                    System.out.println("Thread-1: lock B got.");
                    Demo.sleep1s();
                }
                System.out.println("Thread-1: lock B released.");
            }
            System.out.println("Thread-1: lock A released.");
        }
    }
    
    package com.example.demo.config;
    
    public class Thread2 extends Thread{
        public void run() {
            System.out.println("Thread-2: try get lock B...");
            synchronized (Demo.lockB) {//给B加锁
                System.out.println("Thread-2: lock B got.");
                Demo.sleep1s();
                System.out.println("Thread-2: try get lock A...");
                synchronized (Demo.lockA) {//获取A锁
                    System.out.println("Thread-2: lock A got.");
                    Demo.sleep1s();
                }
                System.out.println("Thread-2: lock A released.");
            }
            System.out.println("Thread-2: lock B released.");
        }
    }
    
    package com.example.demo.config;
    
    
    public class Demo {
        static final Object lockA = new Object();
        static final Object lockB = new Object();
        private Integer value=0;
        private Integer another=0;
    
        public Integer getValue() {
            return value;
        }
    
        public void setValue(Integer value) {
            this.value = value;
        }
    
        public Integer getAnother() {
            return another;
        }
    
        public void setAnother(Integer another) {
            this.another = another;
        }
    
        public void add(int m) {
            synchronized (lockA) { // 获得lockA的锁
                System.out.println("获得lockA的锁0");
                this.value += m;
                synchronized (lockB) { // 获得lockB的锁
                    System.out.println("获得lockB的锁0");
                    this.another += m;
                } // 释放lockB的锁
            } // 释放lockA的锁
        }
    
        public void dec(int m) {
            synchronized (lockB) { // 获得lockB的锁
                System.out.println("获得lockB的锁1");
                this.another -= m;
                synchronized (lockA) { // 获得lockA的锁
                    System.out.println("获得lockA的锁1");
    
                    this.value -= m;
                } // 释放lockA的锁
            } // 释放lockB的锁
        }
    
        static void sleep1s() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
                     new  Thread1().start();
                     new  Thread2().start();
    
            Demo demo=new Demo();
            try {
                demo.add(2);
                demo.dec(2);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
    
    }
    
    结果:
    Connected to the target VM, address: '127.0.0.1:51315', transport: 'socket'
    Thread-1: try get lock A...
    Thread-2: try get lock B...
    Thread-2: lock B got.
    Thread-1: lock A got.
    Thread-1: try get lock B...
    Thread-2: try get lock A...
    造成死锁,
    线程1 A加锁后获取B
    线程2 B加锁后获取A
    造成线程1获取B锁进入等待
    线程2获取A锁进入等待,死循环下取
    思维没有好的解决办法,只有停止虚拟机进行解决
    使用ReentrantLock比直接使用synchronized更安全,可以替代synchronized进行线程同步。
    
    但是,synchronized可以配合wait和notify实现线程在条件不满足时等待,条件满足时唤醒,用ReentrantLock我们怎么编写wait和notify的功能呢?
    
    答案是使用Condition对象来实现wait和notify的功能。
    
    我们仍然以TaskQueue为例,把前面用synchronized实现的功能通过ReentrantLock和Condition来实现
    
    可见,使用Condition时,引用的Condition对象必须从Lock实例的newCondition()返回,这样才能获得一个绑定了Lock实例的Condition实例。
    
    Condition提供的await()、signal()、signalAll()原理和synchronized锁对象的wait()、notify()、notifyAll()是一致的,并且其行为也是一样的:
    
        await()会释放当前锁,进入等待状态;
    
        signal()会唤醒某个等待线程;
    
        signalAll()会唤醒所有等待线程;
    
        唤醒线程从await()返回后需要重新获得锁。
    
    此外,和tryLock()类似,await()可以在等待指定时间后,如果还没有被其他线程通过signal()或signalAll()唤醒,可以自己醒来:
    
    if (condition.await(1, TimeUnit.SECOND)) {
        // 被其他线程唤醒
    } else {
        // 指定时间内没有被其他线程唤醒
    }
    
    可见,使用Condition配合Lock,我们可以实现更灵活的线程同步。
    
    package com.example.demo.config;
    
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.concurrent.Executors;
    import java.util.concurrent.LinkedBlockingDeque;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Demo {
        private final Lock lock = new ReentrantLock();
        private final Condition condition = lock.newCondition();
        private Queue<String> queue = new LinkedList<>();
    
        public void addTask(String s) throws InterruptedException {
            lock.lock();
            try {
                queue.add(s);
                sleep();
                condition.signalAll();
            } finally {
                System.out.println("锁取消,全部唤醒");
                lock.unlock();
            }
        }
    
        public String getTask() throws InterruptedException {
            lock.lock();
            try {
                while (queue.isEmpty()) {
                    condition.await();
                    sleep();
                    System.out.println("等待了");
                }
                return queue.remove();
            } finally {
                System.out.println("锁取消,进行等待");
                lock.unlock();
            }
        }
    
        static void sleep() throws InterruptedException {
            Thread.sleep(1000);
        }
    
        public static void main(String[] args) throws InterruptedException {
    
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(30,
                    100,//当前线程最大并发数
                    3,
                    TimeUnit.SECONDS,
                    new LinkedBlockingDeque<>(30),//候客区
                    Executors.defaultThreadFactory(),
                    //new ThreadPoolExecutor.AbortPolicy() //满了,再进来的线程,不处理,直接抛异常
                    //new ThreadPoolExecutor.CallerRunsPolicy()//满了,返回回去,这里会让main线程处理
                    //new ThreadPoolExecutor.DiscardPolicy()//满了,再进来的线程,不处理,不会抛异常
                    new ThreadPoolExecutor.DiscardOldestPolicy()//满了,再进来的线程,尝试去获取cpu时间片,会与最早的线程竞争,不会抛异常
            );
    
    
            Demo demo = new Demo();
            for (int i = 0; i < 9; i++) {
                threadPoolExecutor.execute(() -> {
                    demo.addTask("abcd");
                    demo.getTask();
                });
            }
            boolean shutdown = threadPoolExecutor.isShutdown();
    //        threadPoolExecutor.wait(30000);
            if (shutdown) {
                threadPoolExecutor.shutdown();
            }
        }
    }
    
    一点点学习,一丝丝进步。不懈怠,才不会被时代淘汰
  • 相关阅读:
    memcache启动程序/etc/sysconfig/memcached
    shell中的点号
    mysql监控
    secureCRT 中文乱码
    memcache key
    杀死所以数据库进程
    导出表记录
    重建二叉树
    从尾到头打印链表
    二维数组中的查找
  • 原文地址:https://www.cnblogs.com/wangbiaohistory/p/15206260.html
Copyright © 2011-2022 走看看