synchronized 线程同步,添加对象锁与类锁

本文详细介绍了Java中的synchronized关键字,包括其基本概念、如何用于解决线程安全问题、以及如何作为对象锁和类锁来实现代码块和方法级别的同步。通过具体示例说明了synchronized在多线程环境下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

Synchronized 概述

修饰代码块

synchronized this · 对象锁

synchronized  class · 类锁

修饰普通方法 · 对象锁

修饰静态方法 · 类锁


Synchronized 概述

1、编写一个类、方法、代码块时,如果其中的代码可能运行于多线程环境下,那么就要考虑同步的问题.

"线程安全"问题存在于"实例变量"中,如果是方法内部的私有变量,则不存在"线程安全"问题。
如果多个线程共同访问1个对象中的实例变量,则有可能出现"线程安全"问题。

2、Java 中内置了语言级的同步关键字-synchronized,这大大简化了Java 中多线程同步的使用

3、synchronized 是 Java 中的关键字,是一种同步锁,主要用于修饰方法、代码块

4、例如用 Account 实体类表示一个银行账户信息,主程序中生成 100 个子线程,每一个子线程都对此账户存 100 元,然后又取出 100 元,最终账户的余额应该还是 1000 元。如果线程不同步,则运行的结果极可能超出我们的想像,而且是操作的线程越多,错误出现的概率就越大。

注意事项

1)synchronized 可以定义在方法上,但 synchronized 并不属于方法定义的一部分,因此 synchronized 关键字不能被继承。

2)如果父类中的某个方法使用了 synchronized 关键字,即使子类中覆盖了这个方法,子类中的这个方法默认情况下也并不是同步的,必须显式地在子类的方法中加上 synchronized 关键字。

3)接口中的方法不能使用 synchronized 关键字定义

4)构造方法不能使用 synchronized 关键字,但可以使用 synchronized 代码块来进行同步

修饰代码块

1、被 synchronized  修饰的代码块 {} 称为同步代码块,其作用的范围是大括号 {xxx} 中的代码。

synchronized this · 对象锁

1、如下所示:synchronized(this) 是对象锁,作用对象是调用这个代码块的对象,可以同步不同线程中的同一个对象,下面能达到同步的目的。

public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();//同一个对象
        for (int i = 0; i < 3; i++) {
            new Thread(myThread).start();//三个线程使用相同的对象
        }
    }
}

class MyThread implements Runnable {
    private static int count = 9;

    @Override
    public void run() {
        synchronized (this) {//设置对象锁,对不同线程中的同一任务对象有效
            try {
                for (int i = 0; i < 3; i++) {
                    count--;
                    System.out.print(Thread.currentThread().getName() + ":" + (count)+"\t");
                    TimeUnit.MILLISECONDS.sleep(500 + new Random().nextInt(1000));//随机休眠 0.5-1.5秒
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

控制台输出如下:

Thread-0:8    Thread-0:7    Thread-0:6    Thread-2:5    Thread-2:4    Thread-2:3    Thread-1:2    Thread-1:1    Thread-1:0    

new Thread(new MyThread()).start();//如果上面改成这样,此时三个线程使用不同的对象,synchronized (this)对象锁无法同步
//如果使用线程池的方式也是同理,对象锁只对同一个对象有效
    public static void main(String[] args) {
        MyThread myThread = new MyThread();//同一个对象
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 3; i++) {
            executorService.execute(myThread);//多个线程中是同一个对象,对象锁可以同步
            executorService.execute(new MyThread());//多个线程中已经不是同一个对象,所以对象锁无用
        }
    }

synchronized  class · 类锁

1、作用的范围是 synchronized(Class class){xxx} 后面{}括起来的部分,作用的对象是这个类的所有对象——类锁。

2、对不同线程中的所有本类的对象有效

public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            //三个线程使用不同的对象,此时synchronized (this) 对象锁无法同步,必须使用 类锁
            new Thread(new MyThread()).start();
        }
    }
}


class MyThread implements Runnable {
    private static int count = 9;

    @Override
    public void run() {
        synchronized (MyThread.class) {//设置类锁,对本类的所有对象有效
            try {
                for (int i = 0; i < 3; i++) {
                    count--;
                    System.out.print(Thread.currentThread().getName() + ":" + (count) + "\t");
                    TimeUnit.MILLISECONDS.sleep(500 + new Random().nextInt(1000));//随机休眠 0.5-1.5秒
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

控制台输出如下:

Thread-0:8    Thread-0:7    Thread-0:6    Thread-2:5    Thread-2:4    Thread-2:3    Thread-1:2    Thread-1:1    Thread-1:0    

修饰普通方法 · 对象锁

1、这里所说的"普通方法"是指 "非静态方法"

2、被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象,对不同线程中的同一对象有效——对象锁; 

3、一个线程访问一个对象的 synchronized(this){xxx} 代码块、或 synchronized 普通方法时,别的线程可以访问该对象的非synchronized 代码块和方法而不受阻塞。

4、一个线程访问一个对象的 synchronized(this){xxx} 代码块、或 synchronized 普通方法时,别的线程不可以访问该对象的其它synchronized 代码块和方法

    public synchronized void run() {
       //写法一
    }

    //等价于
    public void run() {
       synchronized (this) {
         //写法二
        }
    }

5、编码与上面的“synchronized this · 对象锁”完全一样,这里就不重复粘贴。

修饰静态方法 · 类锁

1、作用的是整个静态方法,作用的对象是这个类的所有对象——类锁; 

2、静态方法是属于类的而不属于对象的,同样 synchronized 修饰的静态方法锁定的是这个类的所有对象。

public class Test {
    public synchronized static void todo() {
        //写法一
    }

    //等价于
    public void info() {
        synchronized (Test.class) {
            //写法二
        }
    }
}

3、静态方法随着类的加载而加载,所以对象锁升级为类锁,同一时刻只能有一个线程的对象能访问。

4、编码与上面的 “synchronized  Class · 类锁” 完全一样,这里不再累述。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蚩尤后裔-汪茂雄

芝兰生于深林,不以无人而不芳。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值