前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java中方法锁、对象锁、类锁、静态锁

java中方法锁、对象锁、类锁、静态锁

作者头像
长乐坡头
修改2024-01-11 15:10:18
1350
修改2024-01-11 15:10:18
举报
文章被收录于专栏:时间&空间时间&空间

synchronized关键字,我们一般称之为“同步锁”,用它来修饰需要同步的方法和需要同步代码块,默认是当前对象作为锁的对象。在用类修饰synchronized时(或者修饰静态方法),默认是当前类的Class对象作为锁的对象,故存在着方法锁、对象锁、类锁这样的概念。

先给出以下代码感受下代码执行的时候为什么需要同步?代码可能比较枯燥,配上业务理解起来就会舒服很多,学生军训,有三列,每列5人,需要报数,每个线程负责每一列报数。

代码语言:java
复制
class SynchronizedExample {
    protected static int num = 0;
    protected void numberOff() {
        for(int i=0; i<5; i++) {
            num++;
            System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num);
        }
    }
}

public class SynchronizedTest {
    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample se = new SynchronizedExample();
        for(int i=1; i<=3; i++) {
            new Thread( ()->  {se.numberOff();}, "线程"+i).start();
        }
    }
}

执行结果如下:

之所以出现这种情况,是因为三个线程是异步的,没有同步。对应的业务场景就是,在第一列没有完成报数的时候,其他队列抢报了,这在现实中是不允许的,所以需要类似于synchronized等具有同步功能的关键字粉末登场。

当将报数方法加上synchronized关键字之后,就会一列一列的报数。

代码语言:java
复制

   protected synchronized void numberOff() {
        for(int i=0; i<5; i++) {
            num++;
            System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num);
        }
    }

加锁后代码执行如下:

写到这里还是要从技术层面讲下原理,当一个线程执行带有synchronized关键字的方法时,该线程会在该方法处设置一个锁(其他线程打不开这个锁,只能在外边等该线程释放掉该锁,一般都都是执行玩所有代码逻辑主动释放锁),表示此方法是当前线程独占的,对应到上述业务中就是一次只能有一个队列报数。

一、对象锁

改进后的代码用到了一个对象锁,该对象锁默认是当前对象,上述代码等同于以下代码:

代码语言:java
复制
    protected void numberOff() {
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                num++;
                System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
            }
        }
}

执行代码如下:

当多个线程用一个对象锁,各个线程可以达到同步的作用,如果每个线程都用自己的对象锁,那么synchronized就失去了同步的作用。如以下代码:

代码语言:java
复制
class SynchronizedExample {
    protected static int num = 0;

    protected void numberOff() {
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                num++;
                System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
            }
        }
    }
}

public class SynchronizedTest {

    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample se = new SynchronizedExample();
        for(int i=1; i<=3; i++) {
            new Thread( ()->  {new SynchronizedExample().numberOff();}, "队列"+i).start();
        }
    }
}

执行代码结果如下:

有读者会说不同线程执行的是不同对象中的方法,肯定达不到同步的效果,也对,也很有道理,接着看如下代码:

代码语言:java
复制

class SynchronizedExample {
   protected static int num = 0;

    protected void numberOff(Object lock) {
        synchronized (lock) {
            for (int i = 0; i < 5; i++) {
                num++;
                System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
            }
        }
    }
}

public class SynchronizedTest {
    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample se = new SynchronizedExample();
        for(int i=1; i<=3; i++) {
            new Thread( ()->  {se.numberOff(new Object());}, "队列"+i).start();
        }
    }
}

执行代码结果如下:

三、静态锁

静态锁是针对静态方法而言,当一个静态方法中有synchronized关键字时,默认的是使用当前类字节码对象作为锁。代码示例如下:

代码语言:java
复制
class SynchronizedExample {
    protected static int num = 0;

    protected synchronized static void numberOff() {
        for (int i = 0; i < 5; i++) {
            num++;
            System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
        }
    }
}

public class SynchronizedTest {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 1; i <= 3; i++) {
            new Thread(() -> { new SynchronizedExample().numberOff(); }, "队列" + i).start();
        }
    }
}

代码执行结果如下:

最后用线程池将上述代码写一下:

代码语言:java
复制
package ioo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class SynchronizedExample {
    protected static int num = 0;
    protected synchronized static void numberOff() {
        for (int i = 0; i < 5; i++) {
            num++;
            System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
        }
    }
}

public class SynchronizedTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for(int i=1; i<=3; i++) {
            executorService.execute(() -> new SynchronizedExample().numberOff());
        }
    }
}

执行代码结果如下:

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档