zoukankan      html  css  js  c++  java
  • Java线程安全synchronize学习

    Java中,synchronized关键字有2种用法:

    1. 作为关键字修饰方法
    2. 修饰一个代码块

    线程争用

    为了探究synchronized的具体用法,可以用一个简单的程序来说明:

    package fc.learn.java.synchronize;
    
    import java.util.Random;
    
    public class LearningSynchronized {
    
        public enum SyncTypeTag {
            OBJ_METHOD, CLASS_METHOD, KEYWARD_METHOD, NORMAL_METHOD
        }
    
        static class MyRunnable implements Runnable{
    
            private void counting(){
                for (int i = 0; i< 5; i++){
                    System.out.println(String.format("Thread[%s] count for [%s]", Thread.currentThread().getName(), i));
                    int sleepSeconds = new Random().nextInt();
                    sleepSeconds = sleepSeconds % 10;
                    sleepSeconds = sleepSeconds * sleepSeconds;
                    sleepSeconds = sleepSeconds % 5;
                    System.out.println(String.format("Thread[%s] sleep for 0.%s seconds", Thread.currentThread().getName(), sleepSeconds));
                    try {
                        Thread.sleep(sleepSeconds * 100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            private void synchronizeObjectMethod() {
                synchronized (this){
                    counting();
                }
            }
    
            private void synchronizeClasstMethod(){
                synchronized (MyRunnable.class){
                    counting();
                }
            }
    
            private synchronized void synchronizedMethod(){
                counting();
            }
    
    
            private void normalMethod(){
                counting();
            }
    
            private SyncTypeTag synType;
            public MyRunnable(SyncTypeTag type){
                this.synType = type;
            }
    
            @Override
            public void run() {
                if (this.synType == SyncTypeTag.OBJ_METHOD) {
                    synchronizeObjectMethod();
                } else if (this.synType == SyncTypeTag.CLASS_METHOD) {
                    synchronizeClasstMethod();
                } else if (this.synType == SyncTypeTag.KEYWARD_METHOD) {
                    synchronizedMethod();
                } else if (this.synType == SyncTypeTag.NORMAL_METHOD) {
                    normalMethod();
                }
            }
        }
    
        public static void main(String[] args) {
            Runnable r1 = new MyRunnable(SyncTypeTag.NORMAL_METHOD);
            Runnable r2 = new MyRunnable(SyncTypeTag.NORMAL_METHOD);
    
            Thread t1 = new Thread(r1);
            Thread t2 = new Thread(r2);
    
            t1.start();
            t2.start();
        }
    
    }
    

    运行代码,可以获得结果如下:

    Thread[Thread-1] count for [0]
    Thread[Thread-0] count for [0]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [1]
    Thread[Thread-0] sleep for 0.4 seconds
    Thread[Thread-1] count for [1]
    Thread[Thread-1] sleep for 0.0 seconds
    Thread[Thread-1] count for [2]
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-1] count for [3]
    Thread[Thread-0] count for [2]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [3]
    Thread[Thread-0] sleep for 0.4 seconds
    Thread[Thread-1] count for [4]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-0] count for [4]
    Thread[Thread-0] sleep for 0.1 seconds
    

    也就是说,普通情况下,counting()方法会被线程争用

    类锁 synchronized(class)

    那么我们加锁试试呢?首先试试对class加锁:

    // 之前代码太多不再赘述,此处只展示main方法
    public static void main(String[] args) {
        Runnable r1 = new MyRunnable(SyncTypeTag.CLASS_METHOD);
        Runnable r2 = new MyRunnable(SyncTypeTag.CLASS_METHOD);
    
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
    
        t1.start();
        t2.start();
    }
    

    可以得到如下结果:

    Thread[Thread-0] count for [0]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [1]
    Thread[Thread-0] sleep for 0.0 seconds
    Thread[Thread-0] count for [2]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [3]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [4]
    Thread[Thread-0] sleep for 0.4 seconds
    Thread[Thread-1] count for [0]
    Thread[Thread-1] sleep for 0.0 seconds
    Thread[Thread-1] count for [1]
    Thread[Thread-1] sleep for 0.0 seconds
    Thread[Thread-1] count for [2]
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-1] count for [3]
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-1] count for [4]
    Thread[Thread-1] sleep for 0.1 seconds
    

    此时,线程不再争用,目的达到。

    对象锁 synchronized(object)

    那么试试对象锁:

    // 仔细观察,这里用的 this 也就是说,每个线程用的不是同一把锁
    private void synchronizeObjectMethod() {
        synchronized (this){
            counting();
        }
    }
    
    public static void main(String[] args) {
        Runnable r1 = new MyRunnable(SyncTypeTag.CLASS_METHOD);
        Runnable r2 = new MyRunnable(SyncTypeTag.CLASS_METHOD);
    
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
    
        t1.start();
        t2.start();
    }
    

    运行代码:

    Thread[Thread-1] count for [0]
    Thread[Thread-0] count for [0]
    Thread[Thread-1] sleep for 0.0 seconds
    Thread[Thread-0] sleep for 0.4 seconds
    Thread[Thread-1] count for [1]
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-1] count for [2]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-0] count for [1]
    Thread[Thread-0] sleep for 0.4 seconds
    Thread[Thread-1] count for [3]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-0] count for [2]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [3]
    Thread[Thread-0] sleep for 0.0 seconds
    Thread[Thread-0] count for [4]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-1] count for [4]
    Thread[Thread-1] sleep for 0.0 seconds
    

    可以发现,锁并不起作用。这个原因也很容易理解,因为synchronizeObjectMethod方法中用的synchronized(this)进行加锁,而我们有2个进程对象在对counting()方法进行操作,所以会发生争用。如果代码修改为这样:

    // synchronizedObjectMethod修改成这样:
    private void synchronizeObjectMethod(Object globalLock) {
        synchronized (globalLock){
            counting();
        }
    }
    // 构造方法和成员变量:
    private SyncTypeTag synType;
    private Object globalLock;
    public MyRunnable(SyncTypeTag type, Object lock){
        this.synType = type;
        this.globalLock = lock;
    }
    
    @Override
    public void run() {
        if (this.synType == SyncTypeTag.OBJ_METHOD) {
            synchronizeObjectMethod(this.globalLock);
        } else if (this.synType == SyncTypeTag.CLASS_METHOD) {
            synchronizeClasstMethod();
        } else if (this.synType == SyncTypeTag.KEYWARD_METHOD) {
            synchronizedMethod();
        } else if (this.synType == SyncTypeTag.NORMAL_METHOD) {
            normalMethod();
        }
    }
    
    // main 方法:
    public static void main(String[] args) {
        Object globalLock = new Object();
        Runnable r1 = new MyRunnable(SyncTypeTag.OBJ_METHOD, globalLock);
        Runnable r2 = new MyRunnable(SyncTypeTag.OBJ_METHOD, globalLock);
    
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
    
        t1.start();
        t2.start();
    }
    

    运行代码:

    Thread[Thread-0] count for [0]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [1]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [2]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [3]
    Thread[Thread-0] sleep for 0.0 seconds
    Thread[Thread-0] count for [4]
    Thread[Thread-0] sleep for 0.0 seconds
    Thread[Thread-1] count for [0]
    Thread[Thread-1] sleep for 0.0 seconds
    Thread[Thread-1] count for [1]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-1] count for [2]
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-1] count for [3]
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-1] count for [4]
    Thread[Thread-1] sleep for 0.4 seconds
    

    争用消失。

    关键字 synchronized method()

    接下来再试试synchronized关键字直接修饰方法:

    public static void main(String[] args) {
        Object globalLock = new Object();
        Runnable r1 = new MyRunnable(SyncTypeTag.KEYWARD_METHOD, globalLock);
        Runnable r2 = new MyRunnable(SyncTypeTag.KEYWARD_METHOD, globalLock);
    
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
    
        t1.start();
        t2.start();
    }
    

    运行代码:

    Thread[Thread-0] count for [0]
    Thread[Thread-1] count for [0]
    Thread[Thread-0] sleep for 0.0 seconds
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-0] count for [1]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-1] count for [1]
    Thread[Thread-0] count for [2]
    Thread[Thread-1] sleep for 0.1 seconds
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-0] count for [3]
    Thread[Thread-0] sleep for 0.1 seconds
    Thread[Thread-1] count for [2]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-0] count for [4]
    Thread[Thread-0] sleep for 0.4 seconds
    Thread[Thread-1] count for [3]
    Thread[Thread-1] sleep for 0.4 seconds
    Thread[Thread-1] count for [4]
    Thread[Thread-1] sleep for 0.1 seconds
    

    依旧会起争用,说明synchronized修饰方法,等于 synchronized(this)

    References:
    http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html

  • 相关阅读:
    在CodaLab上提交MURA竞赛的结果
    WEB前端工程师简历
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-list-alt
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-refresh
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-repeat
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-play-circle
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-inbox
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-upload
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-download
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-download-alt
  • 原文地址:https://www.cnblogs.com/tflowingcloud/p/8428743.html
Copyright © 2011-2022 走看看