美文网首页
第一周——Synchronized 关键字理解

第一周——Synchronized 关键字理解

作者: 阳光的nick_lxz | 来源:发表于2018-07-09 14:43 被阅读0次

    synchronized关键字

    主要用于修饰以下三种情况

    一,修饰普通方法。

    private  synchronized void add(){}
    

    eg

    public class TestSync {
    private  int count;
    public static void main(String[] args) {
        final TestSync testSync=new TestSync();
        new Thread(new Runnable() {
            @Override
            public void run() {
                testSync.add();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                testSync.add();
            }
        }).start();
    }
    private  synchronized void add(){
        for (int i = 0; i <10 ; i++) {
            System.out.println(Thread.currentThread().getName()+"--"+count++);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    }
    

    输出结果


    image.png

    可以看到第一个线程执行完成了才会执行第二个线程。如果没有用synchronized修饰的话,结果会是两个线程随机调度。可自行实践。

    二,修饰代码块

    在某些情况下,我们编写的方法体可能比较大,同时存在一些耗时的操作,而需要同步的代码又只有一小部分,如果直接对整个方法进行同步操作,可能会得不偿失。
    我们把add()方法改一下

      private   void add(){
            //其他操作省略....
            synchronized (this){
                for (int i = 0; i <10 ; i++) {
                    System.out.println(Thread.currentThread().getName()+"--"+count++);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    

    得到的结果和上面例子的结果是一样的。假如该方法只有一个for循环。像这样

      private   void add(){
            synchronized (this){
                for (int i = 0; i <10 ; i++) {
                    System.out.println(Thread.currentThread().getName()+"--"+count++);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    

    这样和直接修饰方法是没有区别的。

    三,修饰静态方法

    静态方法是类方法,使用synchronized关键字修饰静态方法得到的类锁。类锁和对象锁不互斥,也就是说多个线程分别调用
    某个类的同步静态方法和同步普通方法,不会是同步的。

    public class TestSync {
        public static void main(String[] args) {
            final TestSync testSync=new TestSync();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    delete();
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    testSync.add();
                }
            }).start();
        }
        private synchronized   void add(){
            //其他操作省略....
         
                for (int i = 0; i <10 ; i++) {
                    System.out.println("线程"+Thread.currentThread().getName()+"执行次数--"+i);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        }
        private  synchronized  static void delete(){
            for (int i = 0; i <10 ; i++) {
                System.out.println("线程"+Thread.currentThread().getName()+"执行次数--"+i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

    结果


    image.png

    多个线程调一个同步静态方法,是互斥的。

           public static void main(String[] args) {
                final TestSync testSync=new TestSync();
                final TestSync testSync2=new TestSync();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                            delete();
                    }
                }).start();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        delete();
                    }
                }).start();
            }
    
            private  synchronized  static void delete(){
                for (int i = 0; i <10 ; i++) {
                    System.out.println("线程"+Thread.currentThread().getName()+"执行次数--"+i);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    

    结果如下图,得出多


    image.png

    上面我们讲到对象锁,什么叫对象锁呢,也就是一个对象只有一把锁,拿到这个锁才能调用被锁的方法,我们试试两个对象

    public class TestSync {
        public static void main(String[] args) {
            final TestSync testSync=new TestSync();
            final TestSync testSync2=new TestSync();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    testSync2.add();
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    testSync.add();
                }
            }).start();
        }
        private synchronized   void add(){
            //其他操作省略....
    
                for (int i = 0; i <10 ; i++) {
                    System.out.println("线程"+Thread.currentThread().getName()+"执行次数--"+i);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        }
        private  synchronized  static void delete(){
            for (int i = 0; i <10 ; i++) {
                System.out.println("线程"+Thread.currentThread().getName()+"执行次数--"+i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    结果


    image.png

    结果很明显,虽然这个add方法是同步的,但是我new了两个对象,调用的时候,并不会互斥。

    总结:

    synchronized关键一般代表的是对象锁,一个对象只有一把锁,在同一个对象内,多个线程调用一个synchronized修饰的非静态方法会互斥。
    如果修饰的是静态方法,则得到的类锁,此时该方法相对于整个类都是同步的,对象锁无关且不互斥。

    参考 https://blog.csdn.net/javazejian/article/details/72828483

    相关文章

      网友评论

          本文标题:第一周——Synchronized 关键字理解

          本文链接:https://www.haomeiwen.com/subject/oahbkftx.html