Java 并发 synchronized 锁

本文参考自大佬 公众号:路人甲java
添加链接描述

当多个线程操作共享数据时会存在数据安全问题,java提供了synchronized可以帮助我们解决,先来看一段代码

package juc;


/**
 * @author yanjun.liu
 * @date 2020/6/28--13:21
 */
public class MySynchronized {

    private static int sum=0;

    public static   void m1(){
        for(int i=0;i<100000;i++){
            sum++;
        }
    }

    public static class T1 extends Thread{

        @Override
        public void run() {
            m1();
        }
    }

    public static void main(String[] args) throws Exception{
        T1 t1 = new T1();
        T1 t2 = new T1();
        T1 t3 = new T1();
        t1.start();
        t2.start();
        t3.start();
        //主线程等待,其他线程执行完成,打印sum
        t1.join();
        t2.join();
        t3.join();
        System.out.println(sum);
    }
}

MySynchronized 中有个静态变量sum,默认值是0,m1()方法中对sum++执行100000次,main方法中创建了3个线程用来调用m1()方法,然后调用3个线程的join()方法,用来等待3个线程执行完毕之后,打印sum的值。我们期望的结果是300000,运行一下,但真实的结果却不是300000。上面的程序在多线程中表现出来的结果和预想的结果不一致,说明上面的程序不是线程安全的。

使用synchronized来修饰静态方法

package juc;


/**
 * @author yanjun.liu
 * @date 2020/6/28--13:21
 * 对于操作共享的资源数据,需要注意数据的安全问题
 */
public class MySynchronized2 {

    private static int sum=0;
    /**
     * synchronized饰静态方法,作用于类的Class对象,进入修饰的静态方法前需要先获取类的Class对象的锁
     */
    public synchronized static   void m1(){
        for(int i=0;i<100000;i++){
            sum++;
        }
    }

    public static class T1 extends Thread{

        @Override
        public void run() {
            m1();
        }
    }

    public static void main(String[] args) throws Exception{
        T1 t1 = new T1();
        T1 t2 = new T1();
        T1 t3 = new T1();
        t1.start();
        t2.start();
        t3.start();
        //主线程等待,其他线程执行完成,打印sum
        t1.join();
        t2.join();
        t3.join();
        System.out.println(sum);
    }
}

加上synchronized修饰会发现输出结构正确300000

使用synchronized来修饰非静态方法(普通方法)

package juc;


/**
 * @author yanjun.liu
 * @date 2020/6/28--13:21
 */
public class MySynchronized {

    private static int sum=0;

    /**
     * synchronized修饰实例方法,作用于当前实例,进入同步代码前需要先获取实例的锁
     */
    public synchronized  void m1(){
        for(int i=0;i<100000;i++){
            sum++;
        }
    }

    public static class T1 extends Thread{
        private MySynchronized mySynchronized;

        public T1(MySynchronized mySynchronized){
            this.mySynchronized=mySynchronized;
        }
        @Override
        public void run() {
            mySynchronized.m1();
        }
    }

    public static void main(String[] args) throws Exception{
        MySynchronized mySynchronized = new MySynchronized();
        //锁实例对象必须是同一个
        T1 t1 = new T1(mySynchronized);
        T1 t2 = new T1(mySynchronized);
        T1 t3 = new T1(mySynchronized);
        t1.start();
        t2.start();
        t3.start();
        //主线程等待,其他线程执行完成,打印sum
        t1.join();
        t2.join();
        t3.join();
        System.out.println(sum);
    }
}

结果输出正常300000
m1()方法是实例方法,三个线程操作m1()时,需要先获取mySynchronized 的锁,没有获取到锁的,将等待,直到其他线程释放锁为止

实例方法上加synchronized,线程安全的前提是,多个线程操作的是同一个实例,如果多个线程作用于不同的实例,那么线程安全是无法保证的
同一个实例的多个实例方法上有synchronized,这些方法都是互斥的,同一时间只允许一个线程操作同一个实例的其中的一个synchronized方法

synchronized同步代码块

package juc;


/**
 * @author yanjun.liu
 * @date 2020/6/28--13:21
 */
public class MySynchronized {

    private static int sum=0;

   private static Integer lock= new Integer(2);

    /**
     * synchronized修饰代码块
     */
    public static class T1 extends Thread{
        private Integer lock;

        public T1(Integer lock){
            this.lock=lock;
        }
        @Override
        public void run() {
           //修饰代码块
            synchronized(lock){
                for(int i=0;i<100000;i++){
                    sum++;
                }
            }
        }
    }

    public static void main(String[] args) throws Exception{
        T1 t1 = new T1(lock);
        T1 t2 = new T1(lock);
        T1 t3 = new T1(lock);
        t1.start();
        t2.start();
        t3.start();
        //主线程等待,其他线程执行完成,打印sum
        t1.join();
        t2.join();
        t3.join();
        System.out.println(sum);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值