java中的Synchronized

为什么要使用Synchronized关键字

在并发的过程中,存在着多个线程共享数据或者数据集的时候,Synchronized可以保证在同一时刻,只有一条线程可以访问某个方法或者某个代码块。

Synchronized加锁的方式
  • 对象锁
    锁的是类的实例对象。

  • 类锁
    锁的是每个类的class对象。每个类的class对象在虚拟机中只有一个,所以类锁也只有一个。

关键字可修饰的地方
  • 代码块
synchronized (Object.class){
            
}
  • 普通方法
public  synchronized void myFunction(){

}

静态方法

public static synchronized void myFunction(){

}
对象锁

在线程非安全的情况下

public class TmpDemo {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        new Thread(()->{
            for (int i = 0;i<100000;i++){
                a.getIncrement();
            }
        },"线程A   ").start();
        new Thread(()->{
            for (int i = 0;i<100000;i++){
                a.getIncrement();
            }
        },"线程B   ").start();

    }
}
class A {
    int index = 0;
    public void getIncrement(){
        index ++ ;
        System.out.println(Thread.currentThread().getName() + index);
    }
}

在上面代码中A ,B两条线程中,分别对 class A 的静态变量进行10w次的自增1,理想的结果输出应该是20w。经过几次测试,数据并不是每次都一样
在这里插入图片描述
在这里插入图片描述
想要达到预期的结果就必须是线程安全的情况下。
那么 加锁的方式可以使用对象锁

public class TmpDemo {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        new Thread(()->{
            synchronized (a){ //给当前对象 a 进行加锁
                for (int i = 0;i<100000;i++){
                    a.getIncrement();
                }
            }
        },"线程A   ").start();
        new Thread(()->{
            synchronized (a){
                for (int i = 0;i<100000;i++){
                    a.getIncrement();
                }
            }
        },"线程B   ").start();

    }
}
class A {
    int index = 0;
    public void getIncrement(){
        index ++ ;
        System.out.println(Thread.currentThread().getName() + index);
    }
}

达到预期的效果
在这里插入图片描述
也可以使用类锁

public class TmpDemo {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        new Thread(()->{
            synchronized (A.class){ //锁住 A.class
                for (int i = 0;i<100000;i++){
                    a.getIncrement();
                }
            }
        },"线程A   ").start();
        new Thread(()->{
            synchronized (A.class){
                for (int i = 0;i<100000;i++){
                    a.getIncrement();
                }
            }
        },"线程B   ").start();

    }
}
class A {
    int index = 0;
    public void getIncrement(){
        index ++ ;
        System.out.println(Thread.currentThread().getName() + index);
    }
}

或者 对A类的getIncreement()方法进行加锁

    public synchronized void getIncrement(){
        index ++ ;
        System.out.println(Thread.currentThread().getName() + index);
    }

这样都能够达到线程安全。

但是在使用对象锁的时候有需要注意的地方,对象锁 锁住的是当前对象的实例。当如果锁住的不是两个相同的实例,这把锁是不生效的。

public class TmpDemo {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        A a1 = new A(); //第二个实例
        new Thread(()->{
            synchronized (a){  //锁住 a
                for (int i = 0;i<100000;i++){
                    a.getIncrement();
                }
            }
        },"线程A   ").start();
        new Thread(()->{
            synchronized (a1){ //锁住 a1
                for (int i = 0;i<100000;i++){
                    a.getIncrement();
                }
            }
        },"线程B   ").start();

    }
}
class A {
    int index = 0;
    public  void getIncrement(){
        index ++ ;
        System.out.println(Thread.currentThread().getName() + index);
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值