• synchronized锁和Lock锁


    synchronized

    对象锁-使用方式1

    public class Demo2 {
        public static void main(String[] args) {
    
            Demo2 demo = new Demo2();
            Thread t1 = new Thread(()->{
                demo.a();
            });
    
            Thread t2 = new Thread(()->{
                demo.b();
            });
    
            t1.start();
            t2.start();
        }
    
        public synchronized void a() {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public synchronized void b() {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    View Code

    上边代码示例中t1和t2两个线程使用同一个Demo2对象分别调用a,b两个方法。两个线程的执行是串行的。因为synchronized在方法上则默认使用当前对象锁。

    public class Demo2 {
        public static void main(String[] args) {
    
    
            Thread t1 = new Thread(()->{
                Demo2 demo = new Demo2();
                demo.a();
            });
    
            Thread t2 = new Thread(()->{
                Demo2 demo = new Demo2();
                demo.b();
            });
    
            t1.start();
            t2.start();
        }
    
        public synchronized void a() {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public synchronized void b() {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    View Code

    在每个线程内创建自己的Demo2对象,两个线程则是并行的。

    对象锁-使用方式2

    public class Demo2 {
        public static void main(String[] args) {
    
            Object lock = new Object();
    
            Demo2 demo = new Demo2();
            Thread t1 = new Thread(() -> {
                demo.a(lock);
            });
    
            Thread t2 = new Thread(() -> {
                demo.b(lock);
            });
    
            t1.start();
            t2.start();
        }
    
        public void a(Object lock) {
            synchronized (lock) {
                try {
                    System.out.println("aaaaaaaaaa");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
        public void b(Object lock) {
            synchronized (lock) {
                try {
                    System.out.println("bbbbbbbbbbbbbbbb");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    View Code

    将synchronized转移到方法内部,组成一个同步代码块,同步代码块接收一个对象类型的参数。在main中创建了一个Object对象,将这个对象分别传递给两个线程的a,b方法。执行结果是串行的,因为两个线程使用的是同一个对象,即同一个锁。

    public class Demo2 {
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                Demo2 demo = new Demo2();
                demo.a();
            });
    
            Thread t2 = new Thread(() -> {
                Demo2 demo = new Demo2();
                demo.b();
            });
    
            t1.start();
            t2.start();
        }
    
        public void a() {
            synchronized (this) {
                try {
                    System.out.println("aaaaaaaaaa");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
        public void b() {
            synchronized (this) {
                try {
                    System.out.println("bbbbbbbbbbbbbbbb");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    View Code

    将代码稍稍修改,每个线程都使用自己的Demo2对象,而同步代码块中写this,这表示每个线程的锁都是自己的Demo2对象,所以结果是并行执行。同步代码块中的对象可以是任意对象,但是使用同一个对象的方法必然会互斥。

    类锁-使用方式1

    public class Demo2 {
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                Demo2.a();
            });
    
            Thread t2 = new Thread(() -> {
                Demo2.b();
            });
    
            t1.start();
            t2.start();
        }
    
        public synchronized static void a() {
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public synchronized static void b() {
            try {
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    View Code

    在static方法上使用synchronizedz则表示synchronized使用的是当前类对象。以上代码是串行执行的。

    类锁-使用方式2

    public class Demo2 {
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                Demo2.a();
            });
    
            Thread t2 = new Thread(() -> {
                Demo2.b();
            });
    
            t1.start();
            t2.start();
        }
    
        public static void a() {
            synchronized (Demo2.class) {
                try {
                    System.out.println("aaaaaaaaaa");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
        public static void b() {
            synchronized (Demo2.class) {
                try {
                    System.out.println("bbbbbbbbbbbbbbbb");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    View Code

    在static方法内部使用synchronized代码块,代码块中只能接收类对象,以上代码传的是同一个类对象Demo2.class。所以执行结果是串行的。

    public class Demo2 {
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                Demo2.a();
            });
    
            Thread t2 = new Thread(() -> {
                Demo2.b();
            });
    
            t1.start();
            t2.start();
        }
    
        public static void a() {
            synchronized (Demo2.class) {
                try {
                    System.out.println("aaaaaaaaaa");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
        public static void b() {
            synchronized (Object.class) {
                try {
                    System.out.println("bbbbbbbbbbbbbbbb");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    View Code

    将代码修改为a和b分别持有Demo2.class和Object.class执行结果是并行的。这种写法可以接收任意的class。

    Lock锁

    在JDK5有了java.util.concurrent包,也就是大家说的JUC,Lock接口在JUC的子包java.util.concurrent.locks中。ReentrantLock是其中的一个实现。

    lock()-unlock()

    public class Test1 {
        public static void main(String[] args) {
    
            ReentrantLock lock = new ReentrantLock();
    
            Test1 test1 = new Test1();
            Thread t1 = new Thread(() -> {
                test1.a(lock);
            });
    
            Thread t2 = new Thread(() -> {
                test1.b(lock);
            });
    
            t1.start();
            t2.start();
        }
    
        public void a(Lock lock) {
            try {
                lock.lock();
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    
        public void b(Lock lock) {
            try {
                lock.lock();
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
    View Code

    a,b两个方法使用的是同一个ReentrantLock对象,只有同一个lock才能有锁的效果,以上代码是串行执行的。lock()加锁,unlock()解锁。它们是同一组操作。

    public class Test1 {
        public static void main(String[] args) {
    
            ReentrantLock lock = new ReentrantLock();
            ReentrantLock lock2 = new ReentrantLock();
    
            Test1 test1 = new Test1();
            Thread t1 = new Thread(() -> {
                test1.a(lock);
            });
    
            Thread t2 = new Thread(() -> {
                test1.b(lock2);
            });
    
            t1.start();
            t2.start();
        }
    
        public void a(Lock lock) {
            try {
                lock.lock();
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    
        public void b(Lock lock) {
            try {
                lock.lock();
                System.out.println("bbbbbbbbbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
    View Code

    如果在增加一个ReentrantLock对象,a,b两个方法使用的不是同一个,运行结果就是并行的。

    tryLock()

    public class Test2 {
        public static void main(String[] args) {
    
            ReentrantLock lock = new ReentrantLock();
    
            Test2 test1 = new Test2();
            Thread t1 = new Thread(() -> {
                test1.a(lock);
            });
    
            Thread t2 = new Thread(() -> {
                test1.b(lock);
            });
    
            t1.start();
            t2.start();
        }
    
        public void a(Lock lock) {
            boolean b = lock.tryLock();
            if (b) {
                try {
                    System.out.println("aaaaaaaaaa");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println("获取锁失败");
            }
        }
    
        public void b(Lock lock) {
            boolean b = lock.tryLock();
            if (b) {
                try {
                    System.out.println("bbbbbbbbbbbbbbbb");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println("获取锁失败");
            }
    
        }
    }
    View Code

    如果一个线程通过tryLock获取锁失败则会返回false,返回true则表示拿到了锁。

    tryLock(long time, TimeUnit unit)

    public class Test3 {
        public static void main(String[] args) {
    
            ReentrantLock lock = new ReentrantLock();
    
            Test3 test1 = new Test3();
            Thread t1 = new Thread(() -> {
                test1.a(lock);
            });
    
            Thread t2 = new Thread(() -> {
                test1.b(lock);
            });
    
            t1.start();
            t2.start();
        }
    
        public void a(Lock lock) {
            boolean b = false;
            try {
                b = lock.tryLock(2, TimeUnit.SECONDS);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    
            if (b) {
                try {
                    System.out.println("aaaaaaaaaa");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println("获取锁失败");
            }
        }
    
        public void b(Lock lock) {
            boolean b = false;
            try {
                b = lock.tryLock(2, TimeUnit.SECONDS);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    
            if (b) {
                try {
                    System.out.println("bbbbbbbbbbbbbbbb");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println("获取锁失败");
            }
    
        }
    }
    View Code

    在设定的time时间内如果还是没有获取到锁,才返回false。

    lockInterruptibly()

    public class Test4 {
        public static void main(String[] args) {
    
            ReentrantLock lock = new ReentrantLock();
    
            Test4 test1 = new Test4();
            Thread t1 = new Thread(() -> {
                test1.a(lock);
            });
    
            Thread t2 = new Thread(() -> {
                test1.b(lock);
            });
    
            t1.start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
            }
            t2.start();
    
          /* t1.interrupt();执行结果
           aaaaaaaaaa
            Exception in thread "Thread-0" java.lang.RuntimeException: aaaaaaaaaaaaaaaa打断施法java.lang.InterruptedException: sleep interrupted
            at com.dfsn.cloud.consumer.locks.Test4.a(Test4.java:51)
            at com.dfsn.cloud.consumer.locks.Test4.lambda$main$0(Test4.java:15)
            at java.lang.Thread.run(Thread.java:748)
            bbbbbbbbb*/
            //   t1.interrupt();
    
      /*    t2.interrupt();的执行结果
            aaaaaaaaaa
            Exception in thread "Thread-1" java.lang.RuntimeException: bbbbbbbbbbbb打断施法java.lang.InterruptedException
            at com.dfsn.cloud.consumer.locks.Test4.b(Test4.java:52)
            at com.dfsn.cloud.consumer.locks.Test4.lambda$main$1(Test4.java:19)
            at java.lang.Thread.run(Thread.java:748)*/
            // t2.interrupt();
        }
    
        public void a(Lock lock) {
            try {
                lock.lockInterruptibly();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    
            try {
                System.out.println("aaaaaaaaaa");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException("aaaaaaaaaaaaaaaa打断施法" + e);
            } finally {
                lock.unlock();
            }
        }
    
        public void b(Lock lock) {
            try {
                lock.lockInterruptibly();
            } catch (Exception e) {
                throw new RuntimeException("bbbbbbbbbbbb打断施法" + e);
            }
    
            try {
                System.out.println("bbbbbbbbb");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
    View Code

    这个方法牵扯到Thread类中的interrupted()方法。对启动的线程使用interrupted方法,则该线程会接收到一个中断的信号,该信号不会停止线程的运行,但如果线程内有调用wait,join,sleep等方法,则会收到一InterruptedException异常。

    使用lockInterruptibly()获取锁,然后调用线程的interrupted()如果当前线程已经获取到了锁正在运行中,线程则会接收一个中断信号量,如上所说。但如果当前线程没有获取到锁,处于等待状态,则lockInterruptibly()也会抛出一个InterruptedException。

    公平锁和非公平锁

    public class Demo5 {
    
        private Lock lock = new ReentrantLock(false);    //如果不传递等于传递false,可以传递true表示公平锁
    
        public static void main(String[] args) throws InterruptedException {
            final Demo5 test = new Demo5();
    
            test.lock.lock();
    
            Thread t1 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t1.start();
    
    
            Thread t2 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t2.start();
    
    
            Thread t3 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t3.start();
    
    
            Thread t4 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t4.start();
    
    
            Thread t5 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t5.start();
    
    
            Thread t6 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t6.start();
    
    
           test.lock.unlock();
    
        }
    View Code

    创建ReentrantLock时如果不传递参数则默认是false非公平锁。如果是公平锁得情况下会根据线程的等待顺序分配锁,而非公平锁则是随机分配。

    ReentrantLock的其他方法

    public class Demo6 extends ReentrantLock{
    
        public static void main(String[] args) throws InterruptedException {
    
            final Demo6 test = new Demo6();
    
            test.lock();
    
            Thread t1 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t1.start();
    
    
            Thread t2 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t2.start();
    
    
            Thread t3 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t3.start();
    
    
            Thread t4 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t4.start();
    
    
            Thread t5 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t5.start();
    
    
            Thread t6 = new Thread() {
                @Override
                public void run() {
                    test.insert(Thread.currentThread());
                }
            };
            t6.start();
    
            System.out.println("查询此锁是否由当前线程持有。"+test.isLocked());
            System.out.println("查询此锁是否由任何线程持有。"+test.isLocked());
            System.out.println("如果此锁的公平设置为true,则返回 true 。"+test.isFair());
            System.out.println("查询是否有线程正在等待获取此锁。"+test.hasQueuedThreads());
            System.out.println("查询给定线程是否等待获取此锁。"+test.hasQueuedThread(t1));
            System.out.println("返回等待获取此锁的线程数的估计。"+test.getQueueLength());
            System.out.println("返回当前拥有此锁的线程,如果不拥有,则返回 null 。"+test.getOwner().getName());
            System.out.println("查询当前线程对此锁的暂停数量。"+test.getHoldCount());
            System.out.println("返回包含可能正在等待获取此锁的线程的集合。"+test.getQueuedThreads().size());
            test.unlock();
            System.out.println("查询此锁是否由当前线程持有。"+test.isLocked());
            Thread.sleep(2000);
            System.out.println("查询是否有线程正在等待获取此锁。"+test.hasQueuedThreads());
            System.out.println("查询给定线程是否等待获取此锁。"+test.hasQueuedThread(t1));
            System.out.println("返回等待获取此锁的线程数的估计。"+test.getQueueLength());
            System.out.println("返回当前拥有此锁的线程,如果不拥有,则返回 null 。"+test.getOwner());
            System.out.println("查询当前线程对此锁的暂停数量。"+test.getHoldCount());
            System.out.println("返回包含可能正在等待获取此锁的线程的集合。"+test.getQueuedThreads().size());
        }
    
    
        public void insert(Thread thread) {
            lock();
            try {
                System.out.println(thread.getName() + "得到了锁");
                Thread.sleep(1000);
            } catch (Exception e) {
                System.out.println(e);
            } finally {
                System.out.println(thread.getName() + "释放了锁");
                unlock();
            }
        }
    }
    View Code

     

     

     

     

     

     

  • 相关阅读:
    线程池
    单例设计模式
    String,StringBuffer,StringBuilder
    马踏棋盘算法
    最短路径问题 (迪杰斯特拉算法,弗洛伊德算法)
    最小生成树 修路问题(普里姆算法,克鲁斯卡尔算法)
    贪心算法 求解集合覆盖问题
    Stream 数组转换
    unittest与pytest对比
    条件编译
  • 原文地址:https://www.cnblogs.com/zumengjie/p/14271112.html
Copyright © 2020-2023  润新知