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");
            }
        }
    }

附录,完整代码

传送带,请点击上车

原文地址:https://www.cnblogs.com/valjeanshaw/p/11393969.html