• synchronized关键字


    并发

    定义

    synchronized方法是java中常用的关键字,属于JVM层面,java的内置锁,Java中的每一个对象都可以作为锁,当对象被synchronized锁住之后,此对象当前是被该锁和该线程独占。

    应用

    分为修饰方法和修饰代码块两大类:具体如下

    • 4种用法:
      1. 修饰实例方法
      2. 修饰静态方法
      3. 同步实例方法中的代码块
      4. 同步静态方法中的代码块
    1. 修饰实例方法
    public synchronized void addOne(){
            try{
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
            num++;
            System.out.println(this.getId()+"  "+num+"  "+System.currentTimeMillis());
      		}
    

    当修饰实例方法时,锁住的是调用该方法的当前对象,即:

    Thread thread1 = new ThreadTest();
    Thread thread2 = new ThreadTest();
    

    thread1和thread2在同一时刻调用是不会产生冲突的,但是thread1和thread2自身内部是会相互竞争的。例,多个线程不能同时调用thread1.addOne()方法。

    1. 修饰静态方法
    public static synchronized void addTwo(){
            try{
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
            count += 2;
            System.out.println("  "+count+"  "+System.currentTimeMillis());
        }
    

    锁住的是当前这个类的Class对象,即:
    当调动 addTwo()方法时,将产生竞争。不论实例对象是什么

    1. 修饰实例方法中的代码块
    public void addThree(){
    
            //使用了“this”,即为调用add方法的实例本身。
            synchronized (this){
                try{
                    Thread.sleep(1000);
                }catch (Exception e){
                    e.printStackTrace();
                }
    
                number += 3;
            }
            System.out.println("  "+number+"  "+System.currentTimeMillis());
        }
    

    重点关注synchronized (this)括号里面。this指定是引用的当前对象,效果和修饰实例方法一致。当()里面是 当前类的class对象时SynchronizedTest.class,效果和修饰静态方法一致。

    1. 修饰静态方法中的代码块
    public static void addFour(){
            synchronized (SynchronizedTest.class){
                try{
                    Thread.sleep(1000);
                }catch (Exception e){
                    e.printStackTrace();
                }
    
                counter += 4;
            }
            System.out.println("  "+counter+"  "+System.currentTimeMillis());
        }
    

    当静态方法时,()里面只能是当前类的class对象 SynchronizedTest.class,效果和修饰静态方法一致。

    synchronized使用的两个细节问题

    1. synchronized锁是可重入锁
      1. 父子类方法的锁可以重入
      2. 同一个对象的两个方法,也可以重入
    public class ReentrantSynchronized extends Father {
    
        /**
         * sychronized   重写父类的方法,锁也可以重入
         */
        @Override
        public synchronized void doSomeThing() {
            super.doSomeThing();
            System.out.println(this.getClass() + "  --  " + Thread.currentThread().getId() + "  --  " + Thread.currentThread().getName());
            System.out.println("ReentrantSynchronized child doSomeThing");
        }
    
        /**
         * sychronized    同一个对象中的两个方法,也可以重入
         */
        public synchronized void doOneThing() {
            System.out.println(this.getClass() + "  --  " + Thread.currentThread().getId() + "  --  " + Thread.currentThread().getName());
            System.out.println("ReentrantSynchronized child doOneThing");
            doAnotherThing();
        }
    
        public synchronized void doAnotherThing() {
            System.out.println(this.getClass() + "  --  " + Thread.currentThread().getId() + "  --  " + Thread.currentThread().getName());
            System.out.println("ReentrantSynchronized child doAnotherThing");
        }
    
        public static void main(String[] args) {
            ReentrantSynchronized reentrantSynchronized = new ReentrantSynchronized();
            reentrantSynchronized.doSomeThing();
            reentrantSynchronized.doOneThing();
        }
    }
    
    class Father {
        public synchronized void doSomeThing() {
            System.out.println(this.getClass() + "  --  " + Thread.currentThread().getId() + "  --  " + Thread.currentThread().getName());
            System.out.println("father doSomeThing()");
        }
    }
    
    1. synchronized锁是自动锁,当抛出异常时,会自动释放锁
    /**
         * 当异常被即时处理掉,未抛出synchronized的修饰区,不会释放锁
         */
        public synchronized void doOneThing() {
            int i = 0;
            while (true) {
                i++;
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("now,the i is:" + i);
    
                try {
                    if (i == 10) {
    					//故意让它抛出异常
                        Integer.parseInt("a");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
    
            }
        }
    
        /**
         * 异常抛出synchronized的修饰区,会释放锁
         */
        public synchronized void doTwoThing() {
            int j = -100;
            while (true) {
                j--;
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("yes boy,the j is:" + j);
    
                if (j == -110) {
                    //故意让它抛出异常
                    Integer.parseInt("a");
                }
            }
        }
    

    附录,完整代码

    传送带,请点击上车

  • 相关阅读:
    mongodb的aggregate聚合操作详解
    2013, Lost connection to MySQL server during query
    事务失败的重试策略
    mongodb的shell脚本
    mongodb的currentOp
    mongodb插入数据
    Too many threads are already waiting
    connection timed out
    python3-request.session 的使用
    intellij-永久破解最新版本idea 2020.3.1
  • 原文地址:https://www.cnblogs.com/valjeanshaw/p/11393969.html
Copyright © 2020-2023  润新知