• Java高并发之魂:synchronized深度解析


    第一章Synchronzied简介

    1、作用

    官方介绍

    翻译:同步方法支持一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读取或写入都是通过同步方法完成的

    一句话说出Synchronized的作用:能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果

    2、地位

    • Synchronized是Java的关键字,被Java语言原生支持
    • 是最基本的互斥同步手段
    • 是并发编程中的元老级角色,是并发编程的必学内容

    3、不使用并发手段的后果演示

    代码实战:两个线程同时a++,最后结果会比预计的少

    public class DisappearRequest1 implements Runnable {
    
        static DisappearRequest1 instance = new DisappearRequest1();
    
        static int i=0;
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println(i);  //运行结果总是小于200000
        }
    
        @Override
        public void run() {
            for (int j=0; j<100000; j++){
                i++;
            }
        }
    }

    原因:count++,它看上去只是一个操作,实际上包含了三个动作:

    1、读取count

    2、将count加一

    3、将count的值写入到内存中

    第二章Synchronized的两种用法

    1、对象锁

    包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(this或自己指定锁对象)

    1⃣️代码块形式:

    this

    public class SynchronizedObjectCodeBlock2 implements Runnable {
    
        static SynchronizedObjectCodeBlock2 instance = new SynchronizedObjectCodeBlock2();
    
        @Override
        public void run() {
            synchronized (this){
                System.out.println("我是对象锁的代码块形式。我叫" + Thread.currentThread().getName());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "运行结束。");
            }
        }
    
        public static void main(String[] args) {
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
            t1.start();
            t2.start();
            while (t1.isAlive() || t2.isAlive()){
    
            }
            System.out.println("finished");
        }
    }

    手动指定锁对象

    不同锁对象

    public class SynchronizedObjectCodeBlock2 implements Runnable {
    
        static SynchronizedObjectCodeBlock2 instance = new SynchronizedObjectCodeBlock2();
    
        Object lock1 = new Object();
        Object lock2 = new Object();
    
        @Override
        public void run() {
            synchronized (lock1){
                System.out.println("我是lock1。我叫" + Thread.currentThread().getName());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "lock1部分运行结束。");
            }
    
            synchronized (lock2){
                System.out.println("我是lock2。我叫" + Thread.currentThread().getName());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "lock2部分运行结束。");
            }
        }
    
        public static void main(String[] args) {
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
            t1.start();
            t2.start();
            while (t1.isAlive() || t2.isAlive()){
    
            }
            System.out.println("finished");
        }
    }

    相同锁对象

    public class SynchronizedObjectCodeBlock2 implements Runnable {
    
        static SynchronizedObjectCodeBlock2 instance = new SynchronizedObjectCodeBlock2();
    
        Object lock1 = new Object();
        Object lock2 = new Object();
    
        @Override
        public void run() {
            synchronized (lock1){
                System.out.println("我是lock1。我叫" + Thread.currentThread().getName());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "lock1部分运行结束。");
            }
    
           synchronized (lock1){
                System.out.println("我是lock2。我叫" + Thread.currentThread().getName());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "lock2部分运行结束。");
            }
        }
    
        public static void main(String[] args) {
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
            t1.start();
            t2.start();
            while (t1.isAlive() || t2.isAlive()){
    
            }
            System.out.println("finished");
        }
    }

    2⃣️方法锁形式:synchronized修饰普通方法,锁对象默认为this

    public class SynchronizedObjectMethod3 implements Runnable {
    
        static SynchronizedObjectMethod3 instance = new SynchronizedObjectMethod3();
    
        public static void main(String[] args) {
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
            t1.start();
            t2.start();
            while (t1.isAlive() || t2.isAlive()){
    
            }
            System.out.println("finished");
        }
    
        @Override
        public void run() {
            method();
        }
    
        public synchronized void method(){
            System.out.println("我的对象锁的方法修饰符形式,我叫" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "运行结束");
        }
    }

    2、类锁

    指synchronized修饰静态的方法或指定锁为Class对象

  • 相关阅读:
    【转】快速Redhat AS4和AS5升级至Centos系统
    linux 控制cpu利用率,已经远程访问linux和文件传输
    linux windows启动问题
    Skyline TEP5.1.3二次开发入门——初级(五)
    Skyline TEP5.1.3二次开发入门——初级(四)
    Skyline TEP5.1.3二次开发入门——初级(三)
    Skyline TEP5.1.3二次开发入门——初级(六)
    基于Skyline的TEP5.1.3实现对矢量SHP文件的加载和渲染
    如何在WPF中嵌入Skyline提供的三维控件
    共享一些可以通过网络访问的MPT地址
  • 原文地址:https://www.cnblogs.com/yanguobin/p/12096279.html
Copyright © 2020-2023  润新知