zoukankan      html  css  js  c++  java
  • 深入研究 synchronized 同步锁 作用于 静态方法 和 非静态方法 的 区别

    1.前言

      众所周知, synchronized 是同步锁 ,虽然在底层又细分了无锁、偏向锁、轻量级锁、自旋锁 以及重量级锁 机制,

    这些底层锁知道一下原理即可 ,【想要 了解 这篇 博文 有 解释 : https://blog.csdn.net/u013256816/article/details/51204385 】

    我这篇随笔专门研究与总结 关于 synchronized 加 在 同一个类里的 静态 和非静态 方法前 有什么不一样的影响 。

    这都是因为我看到的一道题引起的:

    答案是 BE

     

    我想问为什么?

    查找博客资料 ,都是很笼统地解释 

    static的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对
    象),那么static获取到的锁,是属于类的锁。而非static方法获取到的锁,是属于当前对象
    的锁。所以,他们之间不会产生互斥。

     看的我一脸懵逼。。。。。。

    当然可以清楚地知道

    加了synchronized 且有static 的方法称为类锁,

    没有static 的方法称为对象锁。

    经过测试总结:

    (1)多线程使用同一个对象,只允许同时使用一个对象锁,一个类锁,
        其他操作搭配都互斥,只能等前一个线程解锁才能让下一个线程使用;
    (2)多线程分别 new 一个对象,允许同时使用任意的对象锁,也允许对象锁和
    一个类锁同时使用,但是类锁不能够同时使用,会互斥,只能等前一个线程解锁才能让下一个线程使用;

     2.操作

     (1)目录结构

     (2)准备一个含有对象锁和类锁的 类

    package com.example.javabaisc.lock;
    
    public class MSynchronized {
        public synchronized void method1(String name) throws InterruptedException {
            int i = 0;
            while (true) {
                i++;
                System.out.println(name + "我是方法1,当前数字是" + i);
                if (i > 4) {
                    System.out.println(name + "我是方法1,退出");
                    break;
                }
                Thread.sleep(1000);
            }
        }
    
        public synchronized void method2(String name) throws InterruptedException {
            int i = 0;
            while (true) {
                i++;
                System.out.println(name + "我是方法2,当前数字是" + i);
                if (i > 4) {
                    System.out.println(name + "我是方法2,退出");
                    break;
                }
                Thread.sleep(1000);
            }
    
    
        }
    
        public static synchronized void method3(String name) throws InterruptedException {
            int i = 0;
            while (true) {
                i++;
                System.out.println(name + "我是方法3,当前数字是" + i);
                if (i > 4) {
                    System.out.println(name + "我是方法3,退出");
                    break;
                }
                Thread.sleep(1000);
            }
    
    
        }
    
        public static synchronized void method4(String name) throws InterruptedException {
            int i = 0;
            while (true) {
                i++;
                System.out.println(name + "我是方法4,当前数字是" + i);
                if (i > 4) {
                    System.out.println(name + "我是方法4,退出");
                    break;
                }
                Thread.sleep(1000);
            }
    
        }
    }
    View Code

    (3)测试类

    package com.example.javabaisc.lock;
    
    
    public class SynT {
    
        public static void main(String[] args){
        
        }
    }

     内容在测试里详细补充【注意,不可使用@Test注解启动 用户线程,否则所有线程都会随用户线程结束而结束】

    3.测试

    1)测试 :多线程使用同一个对象

     (1)同时使用同一个对象锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
            //共用对象
            MSynchronized mSynchronized = new MSynchronized();
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        mSynchronized.method1("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        mSynchronized.method1("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

     打印结果

     结论:互斥,不能同时使用

    (2)同时使用不同的的对象锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
            //共用对象
            MSynchronized mSynchronized = new MSynchronized();
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        mSynchronized.method1("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        mSynchronized.method2("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

      打印结果

      结论:互斥,不能同时使用

    (3)一个线程使用对象锁,一个使用类锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
            //共用对象
            MSynchronized mSynchronized = new MSynchronized();
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        mSynchronized.method1("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        mSynchronized.method4("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

      打印结果

     结论:可以同时使用

    (4)同时使用同一个类锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
            //共用对象
            MSynchronized mSynchronized = new MSynchronized();
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        mSynchronized.method4("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        mSynchronized.method4("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

     打印结果

      结论:互斥,不能同时使用

     (5)同时使用不同的的类锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
            //共用对象
            MSynchronized mSynchronized = new MSynchronized();
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        mSynchronized.method3("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        mSynchronized.method4("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

    打印结果

       结论:互斥,不能同时使用

    ===================================================================================

                      分割线

    ===================================================================================

    2)测试 :多线程分别 new 一个对象

     (1)同时使用同一个对象锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        MSynchronized mSynchronized = new MSynchronized();
                        mSynchronized.method1("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        MSynchronized mSynchronized2 = new MSynchronized();
                        mSynchronized2.method1("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

    打印结果

      结论:可以同时使用

    (2)同时使用不同的的对象锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        MSynchronized mSynchronized = new MSynchronized();
                        mSynchronized.method1("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        MSynchronized mSynchronized2 = new MSynchronized();
                        mSynchronized2.method2("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

    打印结果

       结论:可以同时使用

    (3)一个线程使用对象锁,一个使用类锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        MSynchronized mSynchronized = new MSynchronized();
                        mSynchronized.method1("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        MSynchronized mSynchronized2 = new MSynchronized();
                        mSynchronized2.method4("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

    打印结果

        结论:可以同时使用

    (4)同时使用同一个类锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        MSynchronized mSynchronized = new MSynchronized();
                        mSynchronized.method4("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        MSynchronized mSynchronized2 = new MSynchronized();
                        mSynchronized2.method4("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

    打印结果

        结论:互斥,不能同时使用

     (5)同时使用不同的的类锁

    package com.example.javabaisc.lock;
    
    public class SynT {
    
        public static void main(String[] args){
    
            Thread s1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("=========我是线程1==========");
                        MSynchronized mSynchronized = new MSynchronized();
                        mSynchronized.method3("我是线程1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
            Thread s2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
    //                    System.out.println("==========我是线程2========");
                        MSynchronized mSynchronized2 = new MSynchronized();
                        mSynchronized2.method4("我是线程2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            //启动
            s1.start();
            s2.start();
        }
    }
    View Code

    打印结果

         结论:互斥,不能同时使用

    4.总结

    (1)在多线程使用同一个对象的测试中,只允许同时使用一个对象锁,一个类锁,
        其他操作搭配都互斥,只能等前一个线程解锁才能让下一个线程使用;
    (2)在多线程分别 new 一个对象的测试中,允许同时使用任意的对象锁,也允许对象锁和
     一个类锁同时使用,但是类锁不能够同时使用,会互斥,只能等前一个线程解锁才能让下一个线程使用;    
  • 相关阅读:
    WPF 附件路由事件
    WPF 中的 路由事件
    WPF 中的DataTemplate 的嵌套
    wpf 的style
    C# 中的反射机制
    如何在github上fork以及同步原作者代码
    c# 执行python方法
    转载:c# 获取CPU温度(非WMI,直接读取硬件)
    C# 多个线程一直跑着While(true)
    C# TextBox控件 显示大量数据
  • 原文地址:https://www.cnblogs.com/c2g5201314/p/13110894.html
Copyright © 2011-2022 走看看