精华内容
下载资源
问答
  • C++ mutex,lock_guard,unique_lock使用说明文档,详细属性介绍,简单使用介绍。
  • java加锁方式

    千次阅读 2021-06-14 17:54:25
    java加锁方式 1、synchronized方式(重量级锁) 加锁方式:synchronized(object)传入对象,不同对象代表不同锁,可以在线程外部新建对象。 public class SellCinemaTicketThread implements Runnable { static ...

    java加锁方式

    1、synchronized方式(重量级锁)

    加锁方式:synchronized(object)传入对象,不同对象代表不同锁,可以在线程外部新建对象。

    public class SellCinemaTicketThread implements Runnable {
        static int num = 100;
        Object object = new Object();
    
        @Override
        public void run() {
            while (true) {
                synchronized (object) {
                    if (num > 0) {
                        System.out.println(Thread.currentThread().getName() + "买票啦---" + num);
                        num--;
                    }
                }
    
            }
        }
    }
    

    也可以作为方法的修饰传入

    public class SellCinemaTicketThread1 implements Runnable {
        static int num = 100;
    
        @Override
        public void run() {
            sell();
        }
    
        private synchronized void sell() {
            while (true) {
                if (num > 0) {
                    System.out.println(Thread.currentThread().getName() + "买票啦---" + num);
                    num--;
                }
            }
        }
    }
    

    2、Lock(比synchronized要轻量级)

    • 新建锁对象Lock l = new ReentrantLock();
    • 加锁 l.lock()
    • 解锁 l.unlock()
    public class TestLockSellTicket implements Runnable {
        static int num = 100;
        Lock l = new ReentrantLock();
    
        @Override
        public void run() {
            while (true) {
                l.lock();
                if (num > 0) {
                    try {
                        Thread.sleep(100);
                        System.out.println("买票啦---" + num);
                        num--;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        l.unlock();
                    }
    
                }
    
            }
    
        }
    }
    

    3、wait() notify() notifyAll()

    /*
    wait() notify() notifyAll() 是Object上的方法,只有Object是对象监视器时候才能调用此方法
        notify() 唤醒同一个对象监视器上的线程
    
        wait(Long timeout) 传入数值,表示超过某个时间还没有被唤醒则自动唤醒
    
        wait和sleep区别:
            sleep() 可以在同步中和同步外使用,线程遇到sleep不释放锁,时间到了继续向下执行
            wait() 只能在同步中使用,由对象监视器调用, 线程进入wait状态时释放掉锁
    
    */
    
    public class TestWaitAndNotify {
        public static void main(String[] args) {
            Object obj = new Object();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (obj) {
                        System.out.println("开始等待。。。。");
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("等待结束。。。。");
                    }
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (obj) {
                        // 休眠两秒再唤醒线程
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        obj.notify();
                    }
                }
            }).start();
        }
    }
    
    

    买票加锁

    SellCinemaTicketThread1类

    
    public class SellCinemaTicketThread1 implements Runnable {
        static int num = 100;
    
        @Override
        public void run() {
            sell();
        }
    
        private synchronized void sell() {
            while (true) {
                if (num > 0) {
                    System.out.println(Thread.currentThread().getName() + "买票啦---" + num);
                    num--;
                }
            }
        }
    }
    

    TestSellCinemaTicket 买票类 多个线程同时卖票

    /*
    
    保持同步:
        代码块加锁  synchronized (任意对象即对象锁) {需要同步的对象}
        方法加锁 在方法返回值前加synchronized
            private synchronized void sell() {同步代码}
    */
    
    public class TestSellCinemaTicket {
        public static void main(String[] args) {
    //        Runnable r = new SellCinemaTicketThread();
            Runnable r = new SellCinemaTicketThread1();
    
            Thread t1 = new Thread(r);
            Thread t2 = new Thread(r);
            Thread t3 = new Thread(r);
    
            t1.start();
            t2.start();
            t3.start();
    
        }
    }
    
    
    展开全文
  • 原来可以这样优化加锁方式!又学到一项新技能!!

    写在前面

    很多时候,我们在并发编程中,涉及到加锁操作时,对代码块的加锁操作真的合理吗?还有没有需要优化的地方呢?

    前言

    在《【高并发】优化加锁方式时竟然死锁了!!》一文中,我们介绍了产生死锁时的四个必要条件,只有四个条件同时具备时才能发生死锁。其中,我们在阻止请求与保持条件时,采用了一次性申请所有的资源的方式。例如在我们完成转账操作的过程中,我们一次性申请账户A和账户B,两个账户都申请成功后,再执行转账的操作。其中,在我们实现的转账方法中,使用了死循环来循环获取资源,直到同时获取到账户A和账户B为止,核心代码如下所示。

    //一次申请转出账户和转入账户,直到成功
    while(!requester.applyResources(this, target)){
        //循环体为空
        ;
    }
    

    如果ResourcesRequester类的applyResources()方法执行的时间非常短,并且程序并发带来的冲突不大,程序循环几次到几十次就可以同时获取到转出账户和转入账户,这种方案就是可行的。

    但是,如果ResourcesRequester类的applyResources()方法执行的时间比较长,或者说,程序并发带来的冲突比较大,此时,可能需要循环成千上万次才能同时获取到转出账户和转入账户。这样就太消耗CPU资源了,此时,这种方案就是不可行的了。

    那么,有没有什么方式对这种方案进行优化呢?

    问题分析

    既然使用死循环一直获取资源这种方案存在问题,那我们换位思考一下。当线程执行时,发现条件不满足,是不是可以让线程进入等待状态?当条件满足的时候,通知等待的线程重新执行?

    也就是说,如果线程需要的条件不满足,我们就让线程进入等待状态;如果线程需要的条件满足时,我们再通知等待的线程重新执行。这样,就能够避免程序进行循环等待进而消耗CPU的问题。

    那么,问题又来了!当条件不满足时,如何实现让线程等待?当条件满足时,又如何唤醒线程呢?

    不错,这是个问题!不过这个问题解决起来也非常简单。简单的说,就是使用线程的等待与通知机制。

    线程的等待与通知机制

    我们可以使用线程的等待与通知机制来优化阻止请求与保持条件时,循环获取账户资源的问题。具体的等待与通知机制如下所示。

    执行的线程首先获取互斥锁,如果线程继续执行时,需要的条件不满足,则释放互斥锁,并进入等待状态;当线程继续执行需要的条件满足时,就通知等待的线程,重新获取互斥锁。

    那么,说了这么多,Java支持这种线程的等待与通知机制吗?其实,这个问题问的就有点废话了,Java这么优秀(牛逼)的语言肯定支持啊,而且实现起来也比较简单。

    用Java实现线程的等待与通知机制

    实现方式

    其实,使用Java语言实现线程的等待与通知机制有多种方式,这里我就简单的列举一种方式,其他的方式大家可以自行思考和实现,有不懂的地方也可以问我!

    在Java语言中,实现线程的等待与通知机制,一种简单的方式就是使用synchronized并结合wait()、notify()和notifyAll()方法来实现。

    实现原理

    我们使用synchronized加锁时,只允许一个线程进入synchronized保护的代码块,也就是临界区。如果一个线程进入了临界区,则其他的线程会进入阻塞队列里等待,这个阻塞队列和synchronized互斥锁是一对一的关系,也就是说,一把互斥锁对应着一个独立的阻塞队列。

    在并发编程中,如果一个线程获得了synchronized互斥锁,但是不满足继续向下执行的条件,则需要进入等待状态。此时,可以使用Java中的wait()方法来实现。当调用wait()方法后,当前线程就会被阻塞,并且会进入一个等待队列中进行等待,这个由于调用wait()方法而进入的等待队列也是互斥锁的等待队列。而且,线程在进入等待队列的同时,会释放自身获得的互斥锁,这样,其他线程就有机会获得互斥锁,进而进入临界区了。整个过程可以表示成下图所示。

    在这里插入图片描述

    当线程执行的条件满足时,可以使用Java提供的notify()和notifyAll()方法来通知互斥锁等待队列中的线程,我们可以使用下图来简单的表示这个过程。

    在这里插入图片描述

    这里,需要注意如下事项:

    (1)使用notify()和notifyAll()方法通知线程时,调用notify()和notifyAll()方法时,满足线程的执行条件,但是当线程真正执行的时候,条件可能已经不再满足了,可能有其他线程已经进入临界区执行。

    (2)被通知的线程继续执行时,需要先获取互斥锁,因为在调用wait()方法等待时已经释放了互斥锁。

    (3)wait()、notify()和notifyAll()方法操作的队列是互斥锁的等待队列,如果synchronized锁定的是this对象,则一定要使用this.wait()、this.notify()和this.notifyAll()方法;如果synchronized锁定的是target对象,则一定要使用target.wait()、target.notify()和target.notifyAll()方法。

    (4)wait()、notify()和notifyAll()方法调用的前提是已经获取了相应的互斥锁,也就是说,wait()、notify()和notifyAll()方法都是在synchronized方法中或代码块中调用的。如果在synchronized方法外或代码块外调用了三个方法,或者锁定的对象是this,使用target对象调用三个方法的话,JVM会抛出java.lang.IllegalMonitorStateException异常。

    具体实现

    实现逻辑

    在实现之前,我们还需要考虑以下几个问题:

    • 选择哪个互斥锁

    在之前的程序中,我们在TansferAccount类中,存在一个ResourcesRequester 类的单例对象,所以,我们是可以使用this作为互斥锁的。这一点大家需要重点理解。

    • 线程执行转账操作的条件

    转出账户和转入账户都没有被分配过。

    • 线程什么时候进入等待状态

    线程继续执行需要的条件不满足的时候,进入等待状态。

    • 什么时候通知等待的线程执行

    当存在线程释放账户的资源时,通知等待的线程继续执行。

    综上,我们可以得出以下核心代码。

    while(不满足条件){
        wait();
    }
    

    那么,问题来了!为何是在while循环中调用wait()方法呢?因为当wait()方法返回时,有可能线程执行的条件已经改变,也就是说,之前条件是满足的,但是现在已经不满足了,所以要重新检验条件是否满足。

    实现代码

    我们优化后的ResourcesRequester类的代码如下所示。

    public class ResourcesRequester{
        //存放申请资源的集合
        private List<Object> resources = new ArrayList<Object>();
        //一次申请所有的资源
        public synchronized void applyResources(Object source, Object target){
            while(resources.contains(source) || resources.contains(target)){
                try{
                    wait();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            resources.add(source);
            resources.add(targer);
        }
        
        //释放资源
        public synchronized void releaseResources(Object source, Object target){
            resources.remove(source);
            resources.remove(target);
            notifyAll();
        }
    }
    

    生成ResourcesRequester单例对象的Holder类ResourcesRequesterHolder的代码如下所示。

    public class ResourcesRequesterHolder{
        private ResourcesRequesterHolder(){}
        
        public static ResourcesRequester getInstance(){
            return Singleton.INSTANCE.getInstance();
        }
        private enum Singleton{
            INSTANCE;
            private ResourcesRequester singleton;
            Singleton(){
                singleton = new ResourcesRequester();
            }
            public ResourcesRequester getInstance(){
                return singleton;
            }
        }
    }
    

    执行转账操作的类的代码如下所示。

    public class TansferAccount{
        //账户的余额
        private Integer balance;
        //ResourcesRequester类的单例对象
        private ResourcesRequester requester;
       
        public TansferAccount(Integer balance){
            this.balance = balance;
            this.requester = ResourcesRequesterHolder.getInstance();
        }
        //转账操作
        public void transfer(TansferAccount target, Integer transferMoney){
            //一次申请转出账户和转入账户,直到成功
            requester.applyResources(this, target))
            try{
                //对转出账户加锁
                synchronized(this){
                    //对转入账户加锁
                    synchronized(target){
                        if(this.balance >= transferMoney){
                            this.balance -= transferMoney;
                            target.balance += transferMoney;
                        }   
                    }
                }
            }finally{
                //最后释放账户资源
                requester.releaseResources(this, target);
            }
        }
    }
    

    可以看到,我们在程序中通知处于等待状态的线程时,使用的是notifyAll()方法而不是notify()方法。那notify()方法和notifyAll()方法两者有什么区别呢?

    notify()和notifyAll()的区别

    • notify()方法

    随机通知等待队列中的一个线程。

    • notifyAll()方法

    通知等待队列中的所有线程。

    在实际工作过程中,如果没有特殊的要求,尽量使用notifyAll()方法。因为使用notify()方法是有风险的,可能会导致某些线程永久不会被通知到!

    展开全文
  • synchronized关键字的四种加锁方式

    千次阅读 2020-03-24 23:23:35
    本篇我们来讲解synchronized关键字的四种加锁使用方式,并对其进行比较。 synchronized对方法加锁 public class SynchronizedTest { static class Thread1 extends Thread { Utils mUtils; Thread1(Utils utils...

    本篇我们来讲解synchronized关键字的四种加锁使用方式,并对其进行比较Github项目地址

    synchronized对方法加锁

    public class SynchronizedTest {
        static class Thread1 extends Thread {
            Utils mUtils;
    
            Thread1(Utils utils) {
                mUtils = utils;
            }
    
            @Override
            public void run() {
                super.run();
                mUtils.method1();
            }
        }
    
        static class Thread2 extends Thread {
            Utils mUtils;
    
            Thread2(Utils utils) {
                mUtils = utils;
            }
    
            @Override
            public void run() {
                super.run();
                mUtils.method2();
            }
        }
    
        static class Utils {
            synchronized void method1() {
                System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
            }
    
            synchronized void method2() {
                System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
            }
        }
    
        public static void main(String[] args) {
            Utils utils = new Utils();
            Utils utils2 = new Utils();
            Thread thread1 = new Thread1(utils);
            Thread thread2 = new Thread2(utils2);
            thread1.start();
            thread2.start();
        }
    }
    //执行结果
    method1 exec before -- threadName:Thread-0
    method2 exec before -- threadName:Thread-1
    method1 exec after-- threadName:Thread-0
    method2 exec after-- threadName:Thread-1
    
    • 我们看到如果对方法整体加锁的话,线程中如果不是同一个Utils对象的话,那么线程0和线程1其实是并行的,并没有达到同步的目的。如果我们仅仅修改运行代码如下,使得传入的对象为同一个对象的话,那么就是同步的效果,如下看到是线程1执行完毕,然后线程2才开始执行:
    public static void main(String[] args) {
            Utils utils = new Utils();
            Thread thread1 = new Thread1(utils);
            Thread thread2 = new Thread2(utils);
            thread1.start();
            thread2.start();
        }
    //执行结果
    method1 exec before -- threadName:Thread-0
    method1 exec after-- threadName:Thread-0
    method2 exec before -- threadName:Thread-1
    method2 exec after-- threadName:Thread-1
    

    使用synchronized(this)

    public class SynchronizedTest2 {
        static class Thread1 extends Thread {
            Utils mUtils;
    
            Thread1(Utils utils) {
                mUtils = utils;
            }
    
            @Override
            public void run() {
                super.run();
                mUtils.method1();
            }
        }
    
        static class Thread2 extends Thread {
            Utils mUtils;
    
            Thread2(Utils utils) {
                mUtils = utils;
            }
    
            @Override
            public void run() {
                super.run();
                mUtils.method2();
            }
        }
    
        static class Utils {
            void method1() {
                synchronized (Utils.this) {
                    System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
                }
            }
    
            void method2() {
                synchronized (Utils.this) {
                    System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
                }
            }
        }
    
        public static void main(String[] args) {
            Utils utils = new Utils();
            Thread thread1 = new Thread1(utils);
            Thread thread2 = new Thread2(utils);
            thread1.start();
            thread2.start();
        }
    }
    //执行结果
    method1 exec before -- threadName:Thread-0
    method1 exec after-- threadName:Thread-0
    method2 exec before -- threadName:Thread-1
    method2 exec after-- threadName:Thread-1
    
    • synchronized(this)代码块加锁,传入同一个对象是同步,如果传入的不是同一个对象,如下所示,则是异步的(线程0和线程1并发执行)。
    public static void main(String[] args) {
            Utils utils = new Utils();
            Utils utils2 = new Utils();
            Thread thread1 = new Thread1(utils);
            Thread thread2 = new Thread2(utils2);
            thread1.start();
            thread2.start();
    }
    //执行结果
    method1 exec before -- threadName:Thread-0
    method2 exec before -- threadName:Thread-1
    method1 exec after-- threadName:Thread-0
    method2 exec after-- threadName:Thread-1
    

    使用synchronized(xxx.class)

    public class SynchronizedTest3 {
        static class Thread1 extends Thread {
            Utils mUtils;
    
            Thread1(Utils utils) {
                mUtils = utils;
            }
    
            @Override
            public void run() {
                super.run();
                mUtils.method1();
            }
        }
    
        static class Thread2 extends Thread {
            Utils mUtils;
    
            Thread2(Utils utils) {
                mUtils = utils;
            }
    
            @Override
            public void run() {
                super.run();
                mUtils.method2();
            }
        }
    
        static class Utils {
            void method1() {
                synchronized (Utils.class) {
                    System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
                }
            }
    
            void method2() {
                synchronized (Utils.class) {
                    System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
                }
            }
        }
    
        public static void main(String[] args) {
            Utils utils = new Utils();
            Thread thread1 = new Thread1(utils);
            Thread thread2 = new Thread2(utils);
            thread1.start();
            thread2.start();
        }
    }
    //执行结果
    method1 exec before -- threadName:Thread-0
    method1 exec after-- threadName:Thread-0
    method2 exec before -- threadName:Thread-1
    method2 exec after-- threadName:Thread-1
    
    • synchronized(xxx.class)加锁方式, 不管线程中传入的是不是同一个对象,都是同步,上面是同一个对象是同步的效果,下面看传入的不是同一个对象的话,效果也是一样的同步。
    public static void main(String[] args) {
            Utils utils = new Utils();
            Utils utils2 = new Utils();
            Thread thread1 = new Thread1(utils);
            Thread thread2 = new Thread2(utils2);
            thread1.start();
            thread2.start();
    }
    //执行结果
    method1 exec before -- threadName:Thread-0
    method1 exec after-- threadName:Thread-0
    method2 exec before -- threadName:Thread-1
    method2 exec after-- threadName:Thread-1
    

    静态方法前加synchronized

    因为静态方法可以直接用类名调用,所以就没有实例化对象,从测试来看也是同步的效果。

    public class SynchronizedTest4 {
        static class Thread1 extends Thread {
            @Override
            public void run() {
                super.run();
                Utils.method1();
            }
        }
    
        static class Thread2 extends Thread {
    
            @Override
            public void run() {
                super.run();
                Utils.method2();
            }
        }
    
        static class Utils {
            synchronized static void method1() {
                System.out.println("method1 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method1 exec after-- threadName:" + Thread.currentThread().getName());
            }
    
            synchronized static void method2() {
                System.out.println("method2 exec before -- threadName:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method2 exec after-- threadName:" + Thread.currentThread().getName());
            }
        }
    
        //synchronized(xxx.class)加锁, 不管线程中传入的是不是同一个对象,都是同步
        public static void main(String[] args) {
            new Thread1().start();
            new Thread2().start();
        }
    }
    //执行结果
    method1 exec before -- threadName:Thread-0
    method1 exec after-- threadName:Thread-0
    method2 exec before -- threadName:Thread-1
    method2 exec after-- threadName:Thread-1
    

    总结:

    下面是对上述结果的总结,从表格中能看出第三种和第四种方式其实是属于同一类的,他们持有的是类锁,而第一个和第二个持有的是对象锁,所以前两个和后两个不会发生互斥现象。

    synchronized加锁方式同步还是异步
    synchronized void methodName()线程中传入的是同一个对象同步,否则异步
    synchronized(this)线程中传入的是同一个对象同步,否则异步
    synchronized(xxx.class)不管线程中传入的是不是同一个对象,都是同步
    synchronized static void methodName()同步
    展开全文
  • synchronized的几种加锁方式

    千次阅读 2020-08-12 12:56:52
    这跟第二个方式其实是同一种。 4、同步代码块传参class对象(全局锁) 所有调用该方法的线程都会实现同步 public class SynchronizedTest { //全局锁,类是全局唯一的 public void test4() { synchronized ...

    1、修饰普通方法(锁住的是当前实例对象)

    • 同一个实例调用会阻塞
    • 不同实例调用不会阻塞

    public class SynchronizedTest {
       //锁住了本类的实例对象
       public synchronized void test1() {
            try {
                logger.info(Thread.currentThread().getName() + " test1 进入了同步方法");
                Thread.sleep(5000);
                logger.info(Thread.currentThread().getName() + " test1 休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
     
        public static void main(String[] args) {
            SynchronizedTest st = new SynchronizedTest();
            SynchronizedTest st2 = new SynchronizedTest();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st.test1();
            }).start();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st2.test1();
            }).start();
     
        }
    }

    此处列举的是不同实例调用的情况 

    2、同步代码块传参this(锁住的是当前实例对象)

    • 同一个实例调用会阻塞
    • 不同实例调用不会阻塞

    public class SynchronizedTest {
       //锁住了本类的实例对象
        public void test2() {
            synchronized (this) {
                try {
                    logger.info(Thread.currentThread().getName() + " test2 进入了同步块");
                    Thread.sleep(5000);
                    logger.info(Thread.currentThread().getName() + " test2 休眠结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
     
        public static void main(String[] args) {
            SynchronizedTest st = new SynchronizedTest();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st.test2();
            }).start();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st.test2();
            }).start();
     
        }
    }

    此处列举的是同一实例调用的情况 

    3、同步代码块传参变量对象 (锁住的是变量对象)

    • 同一个属性对象才会实现同步

    public class SynchronizedTest {
        
       public Integer lockObject;
     
        public SynchronizedTest(Integer lockObject) {
            this.lockObject = lockObject;
        }
     
       //锁住了实例中的成员变量
        public void test3() {
            synchronized (lockObject) {
                try {
                    logger.info(Thread.currentThread().getName() + " test3 进入了同步块");
                    Thread.sleep(5000);
                    logger.info(Thread.currentThread().getName() + " test3 休眠结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public static void main(String[] args) {
            SynchronizedTest st = new SynchronizedTest(127);
            SynchronizedTest st2 = new SynchronizedTest(127);
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st.test3();
            }).start();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st2.test3();
            }).start();
     
        }
    }

    同一个实例对象的成员属性肯定是同一个,此处列举的是不同实例的情况,但是 依旧实现了同步,原因如下:

    Integer存在静态缓存,范围是-128 ~ 127,当使用Integer A = 127 或者 Integer A = Integer.valueOf(127) 这样的形式,都是从此缓存拿。如果使用 Integer A = new Integer(127),每次都是一个新的对象。此例中,两个对象实例的成员变量 lockObject 其实是同一个对象,因此实现了同步。还有字符串常量池也要注意。所以此处关注是,同步代码块传参的对象是否是同一个。这跟第二个方式其实是同一种。

    4、同步代码块传参class对象(全局锁)

    •  所有调用该方法的线程都会实现同步

    public class SynchronizedTest {
     
       //全局锁,类是全局唯一的
        public void test4() {
            synchronized (SynchronizedTest.class) {
                try {
                    logger.info(Thread.currentThread().getName() + " test4 进入了同步块");
                    Thread.sleep(5000);
                    logger.info(Thread.currentThread().getName() + " test4 休眠结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
     
        public static void main(String[] args) {
            SynchronizedTest st = new SynchronizedTest();
            SynchronizedTest st2 = new SynchronizedTest();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st.test4();
            }).start();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st2.test4();
            }).start();
        }
    }

    结果如下: 

     

    5、修饰静态方法(全局锁)

    • 所有调用该方法的线程都会实现同步

    public class SynchronizedTest {
     
       //全局锁,静态方法全局唯一的
        public synchronized static void test5() {
            try {
                logger.info(Thread.currentThread().getName() + " test5 进入同步方法");
                Thread.sleep(5000);
                logger.info(Thread.currentThread().getName() + " test5 休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            SynchronizedTest st = new SynchronizedTest();
            SynchronizedTest st2 = new SynchronizedTest();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st.test5();
            }).start();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                st2.test5();
            }).start();
            new Thread(() -> {
                logger.info(Thread.currentThread().getName() + " test 准备进入");
                SynchronizedTest.test5();
            }).start();
        }
    }

    展开全文
  • 本文将介绍ReentrantLock当中4个加锁方式的使用区别和分析其源码实现的细节差异。 2.使用区别 lock() 不可被中断的获取锁的方式。 tryLock() 尝试一次拿锁,拿不到就返回false,不会像其他方式一样进入阻塞队列...
  • ReentrantLock的四种加锁方式

    千次阅读 2017-10-29 15:22:02
    ReentrantLock的四种加锁方式
  • 在网上搜了搜,有两个办法但都不太好:一个是简单的以进程ID+时间戳,或进程ID+随机数来产生近似的唯一ID,虽简单但对于追求“完美”的... Java中很好解决,这是因为Java程序大多以多线程方式运行,每个线程都能共享Jav
  • Mysql的锁类型、锁模式、加锁方式

    千次阅读 2019-05-23 20:03:55
    通过Mysql服务实现,加锁:lock table xxx read/write,解锁:unlock tables; 当会话将表加上锁后,在锁释放之前,会话只能访问这些加锁的表 表锁里又可以分为读锁和写锁。 表锁的加锁规则: 读锁: 1.持有读锁...
  • 来自:冰河技术 写在前面很多时候,我们在并发编程中,涉及到加锁操作时,对代码块的加锁操作真的合理吗?还有没有需要优化的地方呢?前言在《【高并发】优化加锁方式时竟然死锁了!!》一文...
  • Java 和 数据库进行加锁方式

    千次阅读 2018-12-29 16:37:36
    1.java方式: publicstatic synchronized int generate(StringtableName){  Stringsql = "select value from t_table_id where table_name=?";  Connectionconn = null;  PreparedStatementpstmt ...
  • 多线程的几种加锁方式详解

    万次阅读 2016-07-17 09:47:19
    NSLock NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常使用的,除lock和unlock外,NSLock还...后一个方法则会在指定的Date之前尝试加锁,如果在指定的时间内都不能加锁,则返回NO  synchronized(互斥
  • 写在前面 今天,在优化程序的加锁方式时,竟然出现了死锁!!到底是为什么呢?!经过仔细的分析之后,终于找到了原因。 为何需要优化加锁方式? 在《【高并发】高并发环境下诡异的加锁问题(你加的锁未必安全)》...
  • 传统互斥量加锁方式 <no lock不加锁的方式 <原子函数方式 正文如下: 最近编码需要实现多线程环境下的计数器操作,统计相关事件的次数。下面是一些学习心得和体会。不敢妄称原创,基本是学习笔记。遇到相关的...
  • 并发原子性技术之加锁方式

    千次阅读 2020-02-03 12:15:25
    1. 锁的分类 2. 加锁原理 3. 锁的优化手段 4. java加锁技术
  • JAVA Lock加锁实例

    2018-07-10 16:11:17
    lock.lock()的加锁方式,会使后续请求的线程堵塞等待。(方案A) lock.tryLock()的加锁方式,不会堵塞,会立即返回加锁成功与否。(方案AEX) lock.tryLock(1000, TimeUnit.SECONDS)的加锁方式,允许堵塞时间,若在...
  • 1.这里的两种加锁方式分别指的是synchronized关键字和Lock类。 2.这两种方式的底层实现可以看: Lock底层原理 synchronized的底层实现 3.synchronized和Lock的区别: 实现层面不一样。synchronized 是 ...
  • 此方法通常用于给redis某个key进行加锁 例如: keyA需要加锁,则: $redis->set(keyA_lock, 1, array('nx', 'ex' => 1)); 判断keyA_lock是否存在 如果存在,则keyA已被上锁 解锁的时候,删除相关锁
  • 本文参考文章《论Redis分布式锁的正确使用姿势》总结一下文中提到的7种加锁方式的优缺点。 方案一:SETNX + EXPIRE 优点:实现简单,通过修改过期时间可以支持锁重入,锁超时自动释放; 缺点:因为上述命令是分两步...
  • Java多线程加锁方式

    2020-08-21 00:48:11
    在java中要加锁有两种方式 synchronized修饰 jkd中实现java.util.concurrent.locks.Lock接口的类 ReentrantLock ReentrantReadWriteLock
  • } 显然,可以看到吞吐量低 因为这段程序进行了加锁,而且所有的逻辑都在程序里执行,和数据库的交互也存在时间延迟 二、在数据库中完成 自检操作在数据库中完成,SeckillMapper中添加函数 @Update("update seckill...
  • 这两天在学习Synchronized锁的原理。之前只是知道怎么使用它,但是原理根本不...synchronized的加锁方式有很多种:给代码块加锁、给一般方法加锁、给静态方法加锁,但是不管怎么使用,synchronized锁住的只有两种...
  • iOS开发中不可避免的会遇到加锁的情况,今天就来比较一下各种加锁方式。 目前我所知道的有如下几种加锁方式: 1. @synchronized 关键字加锁 2. NSLock 对象锁 3. NSCondition 4. NSConditionLock 条件锁 5. ...
  • (本文为了方便,英文关键词都都采用小写方式,相关知识点会简单介绍,争取做到可以独立阅读)文章开始我会先介绍本文需要的知识点如下:innodb的聚簇索引(聚集索引)和非聚簇索引(二级索引、非聚集索引)的知识...
  • MySQL InnoDB中各类语句加锁方式 (一)mysql InnoDB事务模型 (二)MySQL InnoDB锁模型 (三)MySQL InnoDB非锁定一致性读与锁定读 (四)MySQL InnoDB锁类型及幻象读问题 (五)MySQL InnoDB...
  • 今天我们就来看看不在方法上加锁的其他加锁方式(下面源代码如无特殊说明都是基于jdk11) 1: concurrentMap 每说到并发的集合类时,都会说到concurrentHashMap ,然后网上一搜可以看到好多相关的概念,segment,链表...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 201,567
精华内容 80,626
关键字:

加锁的方式