Java concurrent synchronized 关键字解析

Java concurrent synchronized 关键字解析

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

  • 代码块
  • 修饰方法
  • 修饰静态的方法
  • 修饰类

修饰代码块DEMO

public class Account {

        public void synchronizedMethod() throws InterruptedException {
            synchronized (this) {
                Thread.sleep(1000);
                //todo

            }
        }


        public void unSynchronizedMethod() {
            //todo
            System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());

        }
    }

修饰代码块时,被修饰的部分在同一时间点只能有一个线程A进入,也就是说一个线程A已经进入Account一个实例 类的方法 synchronizedMethod,那么如果有其他的一个线程B此时想要访问 同一个 Account实例的 synchronizedMethod方法,必须等待已经完成的线程A执行完里边同步的代码块。线程B才能进入同步的代码块;但是如果线程B访问的是 unSynchronizedMethod,那么则不需要等待。

注意 一定是同个Account实例,如果是不同的实例,则没有等待。

修饰方法DEMO

public class Account {

        public synchronized void synchronizedMethod() throws InterruptedException {
            //Thread.sleep(1000);
            //todo

        }


        public void unSynchronizedMethod() {
            //todo
            System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());

        }
    }
    

修饰方法和修饰代码块是一样的,只不过两个的同步的作用域是不同的,修饰方法作用域是整个方法,如果修饰的是代码块,则只是对代码块里边的代码进行同步。

修饰静态方法

/**
 * Created by Jeffy on 17/5/20.
 */
public class Account {

    public static synchronized void synchronizedMethod() throws InterruptedException {
        System.err.println(Thread.currentThread().getName() + " is visiting this method");
        Thread.sleep(5000);
        //todo


    }


    public void unSynchronizedMethod() {
        //todo
        System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());

    }
}

测试类


/**
 * Created by Jeffy on 17/5/20.
 */
public class SynchronizedMain {

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Thread1(new Account()),"thread1").start();
        new Thread(new Thread2(new Account()),"thread2").start();

    }

    static class Thread1 implements Runnable{

        private Account account;

        public Thread1(Account account) {
            this.account = account;
        }

        @Override
        public void run() {
            try {
                account.synchronizedMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    static class Thread2 implements Runnable{

        private Account account;

        public Thread2(Account account) {
            this.account = account;
        }

        @Override
        public void run() {
            try {
                account.synchronizedMethod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

输出

thread1 is visiting this method
thread2 is visiting this method

结果解释,你会发现 thread1 is visiting this method 打印完之后大概用了5秒钟之后 thread2 is visiting this method 才打印出来,说明synchronized修饰的静态方法,同步的是这个Account的所有对象。而并非某一对象。

修饰类

public class Account {

    public void synchronizedMethod() throws InterruptedException {
        synchronized (this.getClass()) {
            System.err.println(Thread.currentThread().getName() + " is visiting this method");
            Thread.sleep(5000);
            //todo

        }
    }


    public void unSynchronizedMethod() {
        //todo
        System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());

    }
}

修饰的效果和修饰静态的方法是一样的,同步的是这个类的所有对象,并非某一个具体的实例。

synchronized关键字注意事项

  • 虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。这两种方式的例子代码如下:
    在子类方法中加上synchronized关键字
  • 在定义接口方法时不能使用synchronized关键字。
  • 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。
  • 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制

你可能感兴趣的:(Java concurrent synchronized 关键字解析)