梳理对Java的synchronized的理解

来源:互联网 发布:数据专员招聘要求 编辑:程序博客网 时间:2024/05/22 05:07

Java的synchronized分为对象锁和类锁。
  1、当多个并发线程访问同一个对象object中的这个synchronized(this)代码块时,一个时间内针对该对象的操作只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
  2、但是,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
  3、当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对该object中所有其它synchronized(this)代码块的访问将被阻塞。
  4、同步加锁的是对象,而不是代码。因此,如果你的类中有一个同步方法,这个方法可以被两个不同的线程同时执行,只要每个线程自己创建一个的该类的实例即可。
  5、不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法。
  6、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。
  7、对一个全局对象或者类加锁时,对该类的所有对象都起作用。
  8.synchronized作用于静态方法和非静态方法的区别
  非静态方法:给对象加锁(可以理解为给这个对象的内存上锁,注意 只是这块内存,其他同类对象都会有各自的内存锁),这时候在其他一个以上线程中执行该对象的这个同步方法(注意:是该对象)就会产生互斥
静态方法: 相当于在类上加锁(*.class 位于代码区,静态方法位于静态区域,这个类产生的对象公用这个静态方法,所以这块内存,N个对象来竞争), 这时候,只要是这个类产生的对象,在调用这个静态方法时都会产生互斥。

Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
普通同步方法,锁是当前实例对象
静态同步方法,锁是当前类的class对象
同步方法块,锁是括号里面的对象

普通方法:
方法A 和方法B同时执行

public class MyObject {    public  void  methodA(){        for (int i = 0; i <5 ; i++) {            System.out.println("methodA -->"+ i);        }    }    public  void  methodB(){        for (int i = 0; i <5 ; i++) {            System.out.println("methodB -->"+ i);        }    }}
public class ThreadA extends Thread {    private MyObject object;    public ThreadA(MyObject object) {        this.object = object;    }    @Override    public void run() {        super.run();        object.methodA();    }}
public class ThreadB extends Thread {    private MyObject object;    public ThreadB(MyObject object) {        this.object = object;    }    @Override    public void run() {        super.run();        object.methodB();    }}
public class Test  {    public static void main(String[] args) {        MyObject object = new MyObject();        //线程A与线程B 持有的是同一个对象:object        ThreadA a = new ThreadA(object);        ThreadB b = new ThreadB(object);        a.start();        b.start();    }}

执行结果

methodA -->0methodB -->0methodB -->1methodB -->2methodB -->3methodB -->4methodA -->1methodA -->2methodA -->3methodA -->4

加了synchronized之后

public class MyObject {    synchronized   public  void  methodA(){        for (int i = 0; i <5 ; i++) {            System.out.println("methodA -->"+ i);        }    }    synchronized  public  void  methodB(){        for (int i = 0; i <5 ; i++) {            System.out.println("methodB -->"+ i);        }    }}

执行结果

methodB -->0methodB -->1methodB -->2methodB -->3methodB -->4methodA -->0methodA -->1methodA -->2methodA -->3methodA -->4

MyObject类中定义有多个synchronized修饰的实例方法时,若多个线程拥有同一个MyObject类的对象,则这些方法只能以同步的方式执行。即,执行完一个synchronized修饰的方法后,才能执行另一个synchronized修饰的方法。

但可以访问非synchronzied方法。
eg:

public class MyObject {    synchronized   public  void  methodA(){        for (int i = 0; i <5 ; i++) {            System.out.println("methodA -->"+ i);        }    }      public  void  methodB(){        for (int i = 0; i <5 ; i++) {            System.out.println("methodB -->"+ i);        }    }   }
public class Test  {    public static void main(String[] args) {        MyObject object = new MyObject();        //线程A与线程B 持有的是同一个对象:object,ThreadB执行的是非synchronized方法        ThreadA a = new ThreadA(object);        ThreadB b = new ThreadB(object);        a.start();        b.start();    }}

执行结果

methodA -->0methodB -->0methodB -->1methodB -->2methodA -->1methodA -->2methodA -->3methodA -->4methodB -->3methodB -->4
public class Test  {    public static void main(String[] args) {        MyObject object = new MyObject();        MyObject object2 = new MyObject();        //线程B与线程D 持有不同对象的同一个非静态synchronized方法:        ThreadB b = new ThreadB(object);        ThreadD d = new ThreadD(object2);        b.start();        d.start();    }}
public class ThreadB extends Thread {    private MyObject object;    public ThreadB(MyObject object) {        this.object = object;    }    @Override    public void run() {        super.run();        object.methodB();    }}
public class ThreadD  extends Thread {    private MyObject object;    public ThreadD(MyObject object) {        this.object = object;    }    @Override    public void run() {        super.run();        object.methodB();    }}
public class MyObject {    public  synchronized void methodB() {        for (int i = 0; i < 10; i++) {            System.out.println(Thread.currentThread().getName() + " ---methodB -->" + i);        }    }}

执行结果

Thread-0 ---methodB -->0Thread-1 ---methodB -->0Thread-1 ---methodB -->1Thread-1 ---methodB -->2Thread-0 ---methodB -->1Thread-1 ---methodB -->3Thread-0 ---methodB -->2Thread-1 ---methodB -->4Thread-0 ---methodB -->3Thread-0 ---methodB -->4Thread-0 ---methodB -->5Thread-1 ---methodB -->5Thread-0 ---methodB -->6Thread-0 ---methodB -->7Thread-0 ---methodB -->8Thread-0 ---methodB -->9Thread-1 ---methodB -->6Thread-1 ---methodB -->7Thread-1 ---methodB -->8Thread-1 ---methodB -->9

由此可见
如果synchronized方法是static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchuronized方法所在对象的对应的Class对象,
因为java中无论一个类有多少个对象,这些对象会对应唯一一个Class 对象,因此当线程分别访问同一个类的两个对象的static,synchronized方法时,他们的执行也是按顺序来的,也就是说一个线程先执行,一个线程后执行。

参考:

https://www.cnblogs.com/cangqiongbingchen/p/5806757.html
https://www.cnblogs.com/hapjin/p/5452663.html

阅读全文
0 0