java 锁 sychronized 笔记

1.引言

最近面试,遇到锁相关的考点,以前学习过可惜忘记了,而且随着工作年限的增长,很多以前搞不懂的,再次理解变得简单,看来有必要看看以前的书了

2.正题

2.1 程序的三要素

  • 原子性
    原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败,有着“同生共死”的感觉。及时在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程所干扰。
int a = 10; //原子操作一个指令 赋值
a++; //2非原子操作,取值,值加1,赋值
int b=a; //3 非原子操作,取值,赋值
a = a+1; //4 非原子操作,取值,加1,赋值
  • 可见性
    可见性是指当一个线程修改了共享变量后,其他线程能够立即得知这个修改,java中用volatile关键字来保证变量的可见性,volatile只能保证可见性 并不能保证有序性

  • 有序性
    有序性就是程序执行的顺序按照代码的先后顺序执行,java中用** sychronized**保证有序性

2.2 sychronized

sychronized 保证原子性和有序性,有以下 三种用法:

public class ThreadTest {
    public synchronized void meathondA() {
        System.out.println("方法A  end"); // 方式1 
    }
    
    public void meathondA1() {
        synchronized (this) {
            System.out.println("方法A  end");// 方式2
        }
    }

    public void meathondA2() {
        synchronized (ThreadTest.class) {
            System.out.println("方法A  end");// 方式3
        }
    }
}

其中方式1 和方式2一样效果,方式3 与方式1,2 不同。

多线程的本质就是:多线程访问公共变量,我的理解分俩种情况。

  • 多线程持有同一个对象,对这个对象的非静态公共变量进行改变
public class VolatileTest {
    public int as = 0;

    public static void main(String[] args) {
        VolatileTest m = new VolatileTest();
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int n = 0; n < 1000; n++) {
                        m.increase();
                    }
                }
            });
            thread.start();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(m.as);
    }

    public synchronized void increase() {
        as++;//取值,加1,赋值
    }
}

输出结果10000

或者这样写

public class VolatileTest {
    public int as = 0;

    public static void main(String[] args) {
        VolatileTest m = new VolatileTest();
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (m) {
                        for (int n = 0; n < 1000; n++) {
                            m.increase();
                        }
                    }
                }
            });
            thread.start();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(m.as);
    }

    public void increase() {
        as++;//取值,加1,赋值
    }
}
  • 多线程对静态变量进行改变
public class VolatileTest {
    public static int as = 0;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (VolatileTest.class) {
                        for (int n = 0; n < 1000; n++) {
                            increase();
                        }
                    }
                }
            });
            thread.start();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(as);
    }

    public static void increase() {
        as++;//取值,加1,赋值
    }
}

总结: 对于静态变量,应该锁Class;对于对象内部的变量,应该锁this/实例对象/方法前加锁

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 九种基本数据类型的大小,以及他们的封装类。(1)九种基本数据类型和封装类 (2)自动装箱和自动拆箱 什么是自动装箱...
    关玮琳linSir阅读 1,918评论 0 47
  • Java内存区域 Java虚拟机在运行程序时会把其自动管理的内存划分为以上几个区域,每个区域都有的用途以及创建销毁...
    架构师springboot阅读 1,795评论 0 5
  • 第6章类文件结构 6.1 概述 6.2 无关性基石 6.3 Class类文件的结构 java虚拟机不和包括java...
    kennethan阅读 968评论 0 2
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,142评论 1 32
  • 以上代码会重复运行 , 不会停止。 JMM(java内存模型) 若想学习好多线程, 那么必须了解一下JMM Jav...
    尼尔君阅读 1,766评论 0 2