欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java的类锁、对象锁和方法锁

程序员文章站 2022-10-04 09:18:11
在Java中,对于synchronized关键字,大家看到的第一反应就是这个关键字是进行同步操作的,即得名“同步锁”。 当用它来修饰方法和代码块时,默认当前的对象为锁的对象,即对象锁。 当用来修饰类和静态方法时,默认当前的类为锁的对象 对象锁 修饰在方法上时,多个线程调用同一对象的同步方法时会阻塞, ......

在java中,对于synchronized关键字,大家看到的第一反应就是这个关键字是进行同步操作的,即得名“同步锁”。

  • 当用它来修饰方法和代码块时,默认当前的对象为锁的对象,即对象锁。

  • 当用来修饰类和静态方法时,默认当前的类为锁的对象

对象锁

修饰在方法上时,多个线程调用同一对象同步方法时会阻塞,调用不同对象同步方法不会阻塞

在多线程环境下,调用不同对象的同步方法:

public class synchronizeddemo {

    public synchronized void syntest(){
        int i = 5;
        while (i-- > 0){
            system.out.println(thread.currentthread().getname() + " : " + i);
            try {
                thread.sleep(500);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
        }
    }

    public static void main(string[] args) {
        synchronizeddemo demo1 = new synchronizeddemo();
        synchronizeddemo demo2 = new synchronizeddemo();

        thread t1 = new thread(new runnable() {
            @override
            public void run() {
                demo1.obj3();
            }
        });

        thread t2 = new thread(new runnable() {
            @override
            public void run() {
                demo2.obj3();
            }
        });

        t1.start();
        t2.start();
    }
}

output:

thread-0 : 4
thread-1 : 4
thread-0 : 3
thread-1 : 3
thread-0 : 2
thread-1 : 2
thread-0 : 1
thread-1 : 1
thread-0 : 0
thread-1 : 0

在多线程环境下,调用同一对象的同步方法:

public class synchronizeddemo {

    public synchronized void syntest(){
        int i = 5;
        while (i-- > 0){
            system.out.println(thread.currentthread().getname() + " : " + i);
            try {
                thread.sleep(500);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
        }
    }

    public static void main(string[] args) {
        synchronizeddemo demo1 = new synchronizeddemo();
        synchronizeddemo demo2 = new synchronizeddemo();

        thread t1 = new thread(new runnable() {
            @override
            public void run() {
                demo1.syntest();
            }
        });

        thread t2 = new thread(new runnable() {
            @override
            public void run() {
                demo1.syntest();
            }
        });

        t1.start();
        t2.start();
    }
}

output:

thread-0 : 4
thread-0 : 3
thread-0 : 2
thread-0 : 1
thread-0 : 0
thread-1 : 4
thread-1 : 3
thread-1 : 2
thread-1 : 1
thread-1 : 0

在多线程环境下,调用不同对象通过this修饰的局部代码块

public class synchronizeddemo {

    public void syntest(){
        synchronized (this){
            int i = 5;
            while (i-- > 0){
                system.out.println(thread.currentthread().getname() + " : " + i);
                try {
                    thread.sleep(500);
                } catch (interruptedexception e) {
                    e.printstacktrace();
                }
            }
        }

    }

    public static void main(string[] args) {

        synchronizeddemo demo1 = new synchronizeddemo();
        synchronizeddemo demo2 = new synchronizeddemo();

        thread t1 = new thread(new runnable() {
            @override
            public void run() {
                demo1.syntest();
            }
        });

        thread t2 = new thread(new runnable() {
            @override
            public void run() {
                demo2.syntest();
            }
        });

        t1.start();
        t2.start();
    }
}

output:

thread-0 : 4
thread-1 : 4
thread-0 : 3
thread-1 : 3
thread-0 : 2
thread-1 : 2
thread-0 : 1
thread-1 : 1
thread-0 : 0
thread-1 : 0

对于this修饰的其实指的就是类的实例,所以它也属于对象锁,并不是类锁。


在多线程环境下,调用不同对象通过其他实例类修饰的局部代码块

public class synchronizeddemo {

    public void syntest(){
        string str = new string("lock");
        synchronized (str){
            int i = 5;
            while (i-- > 0){
                system.out.println(thread.currentthread().getname() + " : " + i);
                try {
                    thread.sleep(500);
                } catch (interruptedexception e) {
                    e.printstacktrace();
                }
            }
        }

    }

    public static void main(string[] args) {

        synchronizeddemo demo1 = new synchronizeddemo();
        synchronizeddemo demo2 = new synchronizeddemo();

        thread t1 = new thread(() -> {
            demo1.syntest();
        });

        thread t2 = new thread(() -> {
            demo2.syntest();
        });

        t1.start();
        t2.start();
    }
}

output:

thread-0 : 4
thread-1 : 4
thread-1 : 3
thread-0 : 3
thread-1 : 2
thread-0 : 2
thread-1 : 1
thread-0 : 1
thread-1 : 0
thread-0 : 0

我们可以看到,我们通过每次调用时实例一个string来进行同步代码块,但是并没有发生阻塞,因为每次生成的是一个实例string,锁的是string,每次都是不一样的,所以不会发生阻塞。


可以通过上述的运行结果可以得到一下结论:

在多线程环境下:

  • 调用不同对象的同步方法,不会发生阻塞
  • 调用相同对象的同步方法,会发生阻塞
  • 调用不同对象通过this修饰的局部代码块,不会发生阻塞
  • 调用不同对象通过其他实例类修饰的同步代码块,不会发生阻塞

类锁

在多线程环境下,多次调用类的静态同步方法:

public class synchronizeddemo {

    public static synchronized void syntest(){
        int i = 5;
        while (i-- > 0){
            system.out.println(thread.currentthread().getname() + " : " + i);
            try {
                thread.sleep(500);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
        }
    }

    public static void main(string[] args) {

        thread t1 = new thread(new runnable() {
            @override
            public void run() {
                synchronizeddemo.syntest();
            }
        });

        thread t2 = new thread(new runnable() {
            @override
            public void run() {
                synchronizeddemo.syntest();
            }
        });

        t1.start();
        t2.start();
    }

output:

thread-0 : 4
thread-0 : 3
thread-0 : 2
thread-0 : 1
thread-0 : 0
thread-1 : 4
thread-1 : 3
thread-1 : 2
thread-1 : 1
thread-1 : 0

在多线程环境下,多次调用被类锁的代码块:

public class synchronizeddemo {
    
    public void syntest(){
        synchronized (synchronizeddemo.class){
            int i = 5;
            while (i-- > 0){
                system.out.println(thread.currentthread().getname() + " : " + i);
                try {
                    thread.sleep(500);
                } catch (interruptedexception e) {
                    e.printstacktrace();
                }
            }
        }

    }

    public static void main(string[] args) {

        synchronizeddemo demo1 = new synchronizeddemo();
        synchronizeddemo demo2 = new synchronizeddemo();

        thread t1 = new thread(new runnable() {
            @override
            public void run() {
                demo1.syntest();
            }
        });

        thread t2 = new thread(new runnable() {
            @override
            public void run() {
                demo2.syntest();
            }
        });

        t1.start();
        t2.start();
    }
}

output:

thread-1 : 4
thread-1 : 3
thread-1 : 2
thread-1 : 1
thread-1 : 0
thread-0 : 4
thread-0 : 3
thread-0 : 2
thread-0 : 1
thread-0 : 0

对于对象synchronizeddemo.class,实际上就是synchronizeddemo这个类,也就是对类进行加锁。

可以通过上述的运行结果可以得到一下结论:

在多线程环境下:

  • 多次调用静态的同步方法,会进行阻塞
  • 不同对象调用被类锁的同步代码块,会进行阻塞

类锁和对象锁同时存在

在多线程环境下,同时调用同一对象的类锁和对象锁

public class synchronizeddemo {

    public static synchronized void synteststatic() {
        int i = 5;
        while (i-- > 0) {
            system.out.println(thread.currentthread().getname() + " : " + i);
            try {
                thread.sleep(500);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
        }
    }

    public synchronized void syntest() {
        int i = 5;
        while (i-- > 0) {
            system.out.println(thread.currentthread().getname() + " : " + i);
            try {
                thread.sleep(500);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
        }
    }

    public static void main(string[] args) {

        synchronizeddemo demo1 = new synchronizeddemo();

        thread t1 = new thread(() -> {
            demo1.syntest();
        });

        thread t2 = new thread(() -> {
            synchronizeddemo.synteststatic();
        });

        t1.start();
        t2.start();
    }
}

output:

thread-1 : 4
thread-0 : 4
thread-1 : 3
thread-0 : 3
thread-1 : 2
thread-0 : 2
thread-1 : 1
thread-0 : 1
thread-1 : 0
thread-0 : 0

我们可以到看到,在多线程环境下,类锁和对象锁同时存在的情况下,多线程访问时不会阻塞,因为他们不是同一个锁。


可以通过上述的运行结果可以得到一下结论:

在多线程环境下:

  • 类锁和对象锁同时存在的情况下,不会发生阻塞

总结

Java的类锁、对象锁和方法锁