美文网首页
Java对象锁和类锁

Java对象锁和类锁

作者: Doooook | 来源:发表于2020-08-10 22:11 被阅读0次

java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。

一、对象锁的synchronized修饰方法和代码块:

/**
 * @author Jay Mitter
 */
public class TestSynchronized {

    /**
     * synchronized修饰代码块
     * this表示当前对象
     */
    public void test1() {
        synchronized (this) {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + ": " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }

    /**
     * synchronized修饰方法
     * 因为第一个同步代码块传入的this,所以两个同步代码所需要获得的对象锁都是同一个对象锁,下面main方法时分别开启两个线程,分别调用test1和test2方法,
     * 那么两个线程都需要获得该对象锁,另一个线程必须等待。上面也给出了运行的结果可以看到:直到test2线程执行完毕,释放掉锁,test1线程才开始执行。
     *
     * 如果我们把test2方法的synchronized关键字去掉:
     * 结果输出是交替着进行输出的,这是因为,某个线程得到了对象锁,但是另一个线程还是可以访问没有进行同步的方法或者代码。进行了同步的方法(加锁方法)
     * 和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)。
     * 这里涉及到内置锁的一个概念(此概念出自java并发编程实战第二章):对象的内置锁和对象的状态之间是没有内在的关联的,虽然大多数类都将内置锁用做一
     * 种有效的加锁机制,但对象的域并不一定通过内置锁来保护。当获取到与对象关联的内置锁时,并不能阻止其他线程访问该对象,当某个线程获得对象的锁之后,
     * 只能阻止其他线程获得同一个锁。之所以每个对象都有一个内置锁,是为了免去显式地创建锁对象。
     *
     * 所以synchronized只是一个内置锁的加锁机制,当某个方法加上synchronized关键字后,就表明要获得该内置锁才能执行,并不能阻止其他线程访问不需要获得该内置锁的方法。
     */
    public synchronized void test2() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        final TestSynchronized myt2 = new TestSynchronized();
        Thread test1 = new Thread(() -> myt2.test1(), "test1");
        Thread test2 = new Thread(() -> myt2.test2(), "test2");
        test1.start();
        test2.start();
        // TestRunnable tr = new TestRunnable();
        // Thread test3 = new Thread(tr);
        // test3.start();
    }
image.png

上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象;第二个方法是修饰方法的方式进行同步。因为第一个同步代码块传入的this,所以两个同步代码所需要获得的对象锁都是同一个对象锁,下面main方法时分别开启两个线程,分别调用test1和test2方法,那么两个线程都需要获得该对象锁,另一个线程必须等待。
如果我们把test2方法的synchronized关键字去掉:


image.png

上面是执行结果,我们可以看到,结果输出是交替着进行输出的,这是因为,某个线程得到了对象锁,但是另一个线程还是可以访问没有进行同步的方法或者代码。进行了同步的方法(加锁方法)和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)。
synchronized只是一个内置锁的加锁机制,当某个方法加上synchronized关键字后,就表明要获得该内置锁才能执行,并不能阻止其他线程访问不需要获得该内置锁的方法。

二、类锁的修饰(静态)方法和代码块:

/**
 * @author Jay Mitter
 */
public class TestSynchronized2 {

    /**
     * 类锁修饰代码块
     */
    public void test1() {
        synchronized (TestSynchronized2.class) {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }

    /**
     * 类锁修饰静态方法
     */
    public static synchronized void test2() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
        }
    }

    /**
     * 其实,类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,
     * 所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。其实这里的重点在下面这块代码,synchronized同时修饰静态和非静态方法
     * @param args
     */
    public static void main(String[] args) {
        final TestSynchronized2 myt2 = new TestSynchronized2();
        Thread test1 = new Thread(() -> myt2.test1(), "test1");
        Thread test2 = new Thread(() -> TestSynchronized2.test2(), "test2");
        test1.start();
        test2.start();
        //         TestRunnable tr=new TestRunnable();
        //         Thread test3=new Thread(tr); 
        //         test3.start(); 
    }

} 
image.png

其实,类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。

三、synchronized同时修饰静态和非静态方法

/**
 * @author pengjinsen
 * synchronized同时修饰静态和非静态方法
 * 运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。
 * 同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。
 */
public class TestSynchronized3 {

    public synchronized void test1() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
        }
    }
 
    public static synchronized void test2() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
        }
    }
 
    public static void main(String[] args) {
        final TestSynchronized3 myt2 = new TestSynchronized3();
        Thread test1 = new Thread(() -> myt2.test1(), "test1");
        Thread test2 = new Thread(() -> TestSynchronized3.test2(), "test2");
        test1.start();
        test2.start();
        //         TestRunnable tr=new TestRunnable(); 
        //         Thread test3=new Thread(tr); 
        //         test3.start(); 
    }
 
}
image.png

上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。
同样,synchronized同时修饰代码块和实例方法,但是运行结果是交替进行的:

/**
 * @author Jay Mitter
 */
public class TestSynchronized2 {

    /**
     * 类锁修饰代码块
     */
    public void test1() {
        synchronized (TestSynchronized2.class) {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }

    /**
     * 类锁修饰静态方法
     */
    public static synchronized void test2() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
        }
    }

    public synchronized void test3() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
        }
    }

    /**
     * 其实,类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,
     * 所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。其实这里的重点在下面这块代码,synchronized同时修饰静态和非静态方法
     * @param args
     */
    public static void main(String[] args) {
        final TestSynchronized2 myt2 = new TestSynchronized2();
        Thread test1 = new Thread(() -> myt2.test1(), "test1");
        Thread test2 = new Thread(() -> TestSynchronized2.test2(), "test2");
        Thread test3 = new Thread(() -> myt2.test3(), "test3");
        test1.start();
        // test2.start();
        test3.start();
        //         TestRunnable tr=new TestRunnable();
        //         Thread test3=new Thread(tr); 
        //         test3.start(); 
    }

}
image.png
参考:https://www.cnblogs.com/owenma/p/8609348.html

相关文章

  • 让你不再害怕JAVA的锁(一)

    java中的同步锁包括对象锁和类锁。 对象锁: 针对的是具体的对象实例;类锁:针对的是整个class类 现在先让我...

  • Java对象锁和类锁

    java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的...

  • 线程、多线程和线程池 二

    1.对象锁和类锁是否会互相影响? · 对象锁:Java的所有对象都含有1个互斥锁,这个锁由JVM自动...

  • 多线程开发艺术之对象锁和类锁

    一.对象锁和类锁是否会互相影响? ·对象锁:Java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程...

  • MySQL的锁怎么解?

    大家都知道java里面的synchronized,对象锁。(这里不扯什么类锁,对象锁,类锁其实就是Class对象的...

  • java-summery

    1、对象锁和类锁 java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码...

  • java类锁和对象锁

    java对象锁有两种:对象锁、类锁。 对象锁:在非静态方法上加锁。声明了一个对象锁。类锁:在静态方法上加锁,声明了...

  • 高并发篇

    高并发篇 java锁有那些 synchronized和lock的区别 synchronized的类锁和对象锁的区别...

  • synchronized

    类锁和对象锁

  • 05.锁机制和条件对象简述

    Java的锁机制主要分内置锁(隐式锁)和显式锁。 内置锁 Java每个对象都有一个内置的锁对象,这些锁对象不需要显...

网友评论

      本文标题:Java对象锁和类锁

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