多线程之对象锁、类锁,引用锁

本文详细介绍了Java中的锁机制,包括类锁、对象锁和引用锁。类锁通过静态方法或同步代码块锁定类本身,对象锁则是针对实例方法或同步代码块,确保同一时刻只有一个线程访问。引用锁则可以通过类的静态引用或实例引用实现类似的效果,控制对特定资源的访问。文章通过示例代码展示了各种锁的使用和竞争关系。
摘要由CSDN通过智能技术生成

我们知道在多线程环境下,我们常常需要给一些共享的东西加锁来保证安全性,在访问某个共享资源的时候,就需要获取到它锁,而这个这个锁就分为很多种,类锁、对象锁、引用锁。

结论

1.对于synchronized关键字,作用在方法上,如public (static) synchronized 返回值类型 方法名,如果是静态方法,那么此处的锁就是类锁,如果是普通方法,锁就是对象锁。
2.synchronized(this){…}就代表此处的锁就是对象锁,synchronized(类.class){…}就代表此处锁就是类锁。
3.对于引用锁,synchronized(非静态引用){…},实际上就代表此处的锁就是发挥着和对象锁一样的作用,synchronized(静态引用){…},实际上就代表此处的锁发挥着和类锁一样的作用。
4.一个实例只能有一个对象锁,那么在同一时刻,外部的线程最多只能访问一个被synchronized修饰的方法。

对象锁

所谓对象锁,从名字上看就是锁住对象的锁,对象就是实例,一个类可以有多个实例,每个实例都可以有自己的锁,或者这样说每个实例都都可以锁住属于自己的东西,那么一个类中什么是属于实例的的那,非静态的方法、变量、代码块、,那么作用在这些东西上的锁都可以是对象锁,需要注意的是在java中synchronized不能修饰变量,并且一个实例只能有一个锁对象,只能修饰方法和代码块。所以属于对象的,并且可以加锁的就是非静态方法和非静态代码块。对于方法的加锁方式 :public synchronized void say(){…},对于代码块的加锁方式synchronized(this){ …},代码如下:

/**
 * @author 理想
 * @version 1.0
 * @date 2021/7/16 1:06
 */
public class Test01 {
    public int a=5;
    public static int count=0;
    
    {
        synchronized(this)
        {
            System.out.println( "这是第"+ ++count+"个实例");
        }

    }

    public synchronized void say()
    {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("你好啊"+ ++count);
    }

    public synchronized void eat()
    {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("好好吃");
    }

    public void two()
    {
        synchronized (this)
        {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我是对象锁的另一种表现方式");
        }
    }
}

在主方法中进行测试

/**
 * @author 理想
 * @version 1.0
 * @date 2021/7/16 1:17
 */
public class demo01 {
    public static void main(String[] args) {
        Test01 test01 = new Test01();
        Test01 test02 = new Test01();
        /**
         * 当两个线程同时访问一个对象的时候,线程A获取到了锁,那么线程B就得等待,存在竞争关系
         */
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test01.say();
//            }
//        }).start();
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test01.say();
//            }
//        }).start();

        /**
         * 当两个线程去访问不同的对象的时候,获取的是不同的锁,不存在竞争关系
         */

//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test01.say();
//            }
//        }).start();
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test02.say();
//            }
//        }).start();

        /**
         * 当两个线程同时访问同一个对象里面的不同加锁方法,由于当前的锁是以对象为锁,那么就存在竞争关系
         * 比如说这里 非静态的的say和eat方法都加了synchronized,都是同一个对象的锁,要么say先执行,eat等待,要么执行eat的线程先抢到锁,执行say的
         * 线程等待
         */
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test01.say();
//            }
//        }).start();
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test01.eat();
//            }
//        }).start();

        /**
         * 对象锁实际上也可以用synchronized (this)来,这样的效果实际上是一样的,只是写法不一样,同样也需要竞争
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                test01.two();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test01.two();
            }
        }).start();


    }
}

类锁

类锁的意思就是以当前类对象为锁,以类本身为锁,类锁就很有意思了,锁住自己的东西,静态方法,静态代码快,public static synchronized 返回值类型 方法名,这本身就可以是个类锁,就不用过多解释了,但是你也可以作用非静态代码块上,代码可以像下面这么写,但是我也不知道这么写的意义是什么。
public void sleep02()
{
synchronized (Test02.class)
{

}
}
这个方法还是属于每个对象的,但是当一个对象在使用的时候,其他对象却无法使用这个方法,不知道这种模式的应用在哪。

/**
 * @author 理想
 * @version 1.0
 * @date 2021/7/16 1:41
 */
public class Test02 {

    /**
     * 第一种表现方式
     */
    public  static synchronized void sleep()
    {
        System.out.println("我是类的锁");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 作用在静态代码块
     */

    static {
        synchronized (Test02.class)
        {

        }
    }

    /**
     * 第二种类锁的表现方式
     */
    public void  sleep02()
    {
        /**
         * 作用在非静态代码快
         */
        synchronized (Test02.class)
        {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"来了");
        }
    }
}

在主方法中测试

/**
 * @author 理想
 * @version 1.0
 * @date 2021/7/16 1:42
 */
public class demo02 {
    public static void main(String[] args) {
        Test02 test01 = new Test02();
        Test02 test02 = new Test02();

        /**
         * 对于类锁而言,锁的是属于类的东西,如静态代码块,静态方法
         */
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                Test02.sleep();
//            }
//        }).start();
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                Test02.sleep();
//            }
//        }).start();

        /**
         * 使用类锁,锁住某个非静态方法中的代码块,这样的话,不同的线程去访问不同对象的同一方法也会竞争锁对象
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                test01.sleep02();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test02.sleep02();
            }
        }).start();


    }
}

引用锁

引用锁就是说在类中创建一个任意类型的引用,假如说你创建一个静态的,那么这个引用属于类本身,使用这个引用加锁,就相当于使用类加锁的效果,假如你创建一个非静态的引用,那么这个引用属于实例,每个实例都有,那么使用这个引用加锁,就相当于使用对象锁加锁的效果。测试代码如下


/**
 * @author 理想
 * @version 1.0
 * @date 2021/7/16 2:05
 */
public class Test03 {

        /**
         * 引用锁
         */
        //一个普通的
        Object object=new Object();
        //一个静态的
        static Object object_static=new Object();

        public void happy()
        {
            /**
             * 这是一个普通的成员变量,与锁对象中的this起的作用差不多
             */
            synchronized (object)
            {

                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"非静态变量");
            }
        }

        public void mad()
        {
            /***
             * 静态变量,属于类,与 类.class差不多
             */
            synchronized (object_static)
            {

                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"静态变量");
            }

        }
}

测试类如下

/**
 * @author 理想
 * @version 1.0
 * @date 2021/7/16 2:05
 */
public class demo03 {
    public static void main(String[] args) {
        Test03 test01 = new Test03();
        Test03 test02 = new Test03();

        /**
         * 两个线程去访问两个对象的被非静态引用锁加锁的happy方法,不存在竞争关系
         */
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test01.happy();
//            }
//        }).start();
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                test02.happy();
//            }
//        }).start();
/**
 * 两个线程都去访问被静态引用锁加锁的mad,竞争一个锁,存在竞争关系
 */

        new Thread(new Runnable() {
            @Override
            public void run() {
                test01.mad();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test02.mad();
            }
        }).start();
    }

}

在本中的代码都是根据代码的输出先后,间隔时间来判断是否产生了竞争

这就是我对几种加锁的理解,如有错误,欢迎指出,感激不尽 !

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值