zoukankan      html  css  js  c++  java
  • 呀?这就是锁(一)?

    java常用锁

    Synchroized(自旋锁,轻量级锁)

    package com.LockDemo;
    
    public class SynchronizedDemo {
    
    
        static Object o = new Object();
    
        //synchronized 修饰 m方法
        static synchronized void m1()  {
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } //两个线程会等待,锁生效 此时锁定的对象是 m1 方法
    
        //synchronized 修饰对象
        void m2(){
            synchronized(this){
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }//两个线程会等待,锁生效 此时锁定的是 sd 对象
    
        //synchronized 修饰对象
        void m3(){
            synchronized(this){
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }//不等待,因为两个线程不争用对象资源
    
        static synchronized void m4(){
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }//如果有static 关键字,则会被加锁,反之,锁消失 ,证明在这种情况下,锁定的静态的 m4 方法,而非静态的 m4 每个属于每个线程特有的不加锁
    
        void m5(){
            synchronized (o){
                System.out.println(Thread.currentThread().getName());
                try {
                    //o = new Object(); //o 指向一个新的对象 ,此时synchronized指向的o变成未加锁状态,第二个线程会直接进来,
                    Thread.sleep(10000);
                    o = new Object(); //此时再释放,则会等待10s
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } //o在sleep前指向新的o,synchronized立刻失效,直接输出两个线程名字,反之则等待后输出
    
        public static void main(String[] args) {
            //m2 使用
            SynchronizedDemo sd = new SynchronizedDemo();
            new Thread(()->{
                /*
                    m1(); //m1
                    sd.m2(); //m2
                    new SynchronizedDemo().m3(); //m3
                 */
                new SynchronizedDemo().m5();
            }).start();
    
            //m4 第二种调用
            /*
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    new SynchronizedDemo().m4();
                }
            };
            new Thread(r).start();
            new Thread(r).start();
            */
            new SynchronizedDemo().m5(); //使用m4方式需要注释
        }
    
    }
    

    总结:

    synchronized肯定会对一个对象加锁来实现并发,如果没有达到想要的目的,需要分析加锁对象是不是竞争线程都需要,如果你在TheadA给A加上了锁,但是ThreadB却不会使用A,那么这个锁就没有意义,并且在锁定过程中,对象不能更改,如果更改就相当于把锁加到了一个没有引用的对象上,没有意义,此时新的指向已经是无锁对象了,

    备注:

    异常会把锁丢失,所以需要异常处理严谨一些。

    ReentrantLock (互斥锁,独占锁)

    package com;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * ReentrantLock和synchronized的基本用法相同,所以首先要理解synchronied的实现原理,
     * 这里主要讲述ReentranrLock相对于synchronized增强的部分
     */
    public class ReeLockDemo {
    
        static ReentrantLock reeLock = new ReentrantLock();
    
        //普通加锁解锁
        static void m1(){
            try {
                //System.out.println(Thread.currentThread().getName()+"1"); //此处可以直接输出,即不加锁部分
                reeLock.lock();
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                reeLock.unlock(); //必须要消除锁
            }
        }//此时锁定的reeLock.lock()到reeLock.unlock()中间的部分
    
    
        //尝试加锁
        static void m2(){
            boolean locked = false;
            try {
                locked = reeLock.tryLock();
                if(locked){
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(10000);
                }
                System.out.println(Thread.currentThread().getName()+locked); //这里输出Thread-0 false,因为此时的锁被main线程占用
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                if(locked) reeLock.unlock(); //必须要消除锁,必须加上判断,不然如果没有获得锁便会直接报措,错误是
                /* Exception in thread "Thread-0" java.lang.IllegalMonitorStateException 锁状态不合法,因为没有锁,直接释放当然状态不对
                at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
                at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
                at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
                 */
            }
        }
    
        //等待锁资源可以被打断了
        static void m3(){
            boolean locked = false;
            try {
                reeLock.lockInterruptibly();
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                if(locked) reeLock.unlock();
            }
            /*
            输出结果
                main
                java.lang.InterruptedException
                    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
                    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
                    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
                    at com.ReeLockDemo.m3(ReeLockDemo.java:53)
                    at com.ReeLockDemo.lambda$main$0(ReeLockDemo.java:68)
                    at java.lang.Thread.run(Thread.java:748)
                    明显可以看到t1线程没有再等待锁,打断等待状态
             */
        }
        //真的公平吗?
        static void m4(){
            ReentrantLock fairLock = new ReentrantLock(true); //这里我们设定的是公平锁
            try {
                fairLock.lock();
                System.out.println(Thread.currentThread().getName());
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                fairLock.unlock(); //必须要消除锁
    
    //            try {
    //                Thread.sleep(1000);
    //            } catch (InterruptedException e) {
    //                e.printStackTrace();
    //            }
    //
                //如果有sleep结果是这样的,节选一部分
                /*
                Thread-1
                Thread-0
                Thread-1
                Thread-0
                Thread-1
                Thread-0
                 */
                //如果没有sleep结果是这样的,节选一部分
                /*
                Thread-0
                Thread-0
                Thread-0
                Thread-1
                Thread-1
                Thread-1
                Thread-1
                 */
                /*
                从上面的结果不难发现,这个公平好像和想的不一样,这是因为,再系统内部是否公平是根据排队的顺序来的,即便是ThreadA刚刚被执行了一次,如果他第二次排队又排到
                ThreadB的前面,那么他还是会继续执行,这样想就容易明白了
                 */
            }
        }
    
        public static void main(String[] args) {
            /*
            Thread t1 = new Thread(()->{
                //m1();
                m3();
            });//.start();
    
            //m1();
            //m2();
    
            //执行m3方法
            t1.start();
            //首先指向main中m3 ,2S 后释放
            try {
                m3();
                Thread.sleep(2000);
                t1.interrupt(); //t1不再等待锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
             */
            //m5
            Thread t1 = new Thread(()->{
               while(true){
                   m4();
               }
            });
            Thread t2 = new Thread(()->{
                while(true){
                    m4();
                }
            });
    
            t1.start();
            t2.start();
    
        }
    }
    

    总结:

    ReentrantLock和synchronized相比更加的灵活,并且需要显示的加锁和释放锁,所以也需要我们对它有更加深刻的理解,才能再使用的过程中有的放矢,有效的提升工作效率。

  • 相关阅读:
    怎样运用好ZBrush中的布尔运算
    怎样用好ZBrush 中的映射大师功能
    jvm
    java8 新用法
    entity framework delete table Error 11007:
    'EF.Utility.CS.ttinclude' returned a null or empty string.
    js判断是否绑定了事件。
    线程每5分钟刷新一次
    http请求提交cookie
    javascrip小笔记
  • 原文地址:https://www.cnblogs.com/aierben/p/14753008.html
Copyright © 2011-2022 走看看