synchronized使用总结
java多线程同步处理经常会使用到synchronized关键字,之前对其使用场景有些模糊不清,故做一些整理。
一、使用synchronized修饰非静态方法
1 public class Hello{ 2 3 public synchronized void sayHello(){ 4 System.out.println("Hello world"); 5 } 6 }
这种方式是对每一个Hello对象上锁,第一个访问该方法的线程A则持有当前Hello对象的锁,线程B要访问该对象的线程会被阻塞,直到线程A访问结束释放该对象的锁线程B才能访问。但是如果线程B访问的是Hello的另外一个对象,则不会被阻塞,因为sayHello是一个非静态方法。
二、使用synchronized修饰静态方法
1 public class Hello{ 2 3 public synchronized static void sayHello(){ 4 System.out.println("Hello world"); 5 } 6 }
static关键字修饰的方法表示该方法是一个类方法,与类的对象无关,所以当线程A首先持有了sayHello的锁后,线程B无论访问Hello的那个对象都会阻塞。
三、使用synchronized同步块
前面两种方法虽然能实现同步,但是效率不是很高。假设Hello有两个被synchronized修饰的方法。当线程A访问sayHello()时会持有Hello对象的锁,这时,如果线程B
去访问sayBye()时会被阻塞,因为访问syaBye()需要持有Hello对象的锁。有时候可能sayHello()和syaBye()并发不会有影响,这样做就会降低程序效率。
public class Hello { public synchronized void sayHello() { System.out.println("Hello world"); } public synchronized void sayBye() { System.out.println("bye bye"); } }
所以java有了synchronized同步块的使用,同步块也可以分为两种。静态和非静态。
非静态同步块:
public class Hello { private final Object lockHello = new Object(); private final Object lockBye = new Object(); public void sayHello(){ synchronized (lockHello) { System.out.println("hello"); } } public synchronized void sayBye() { synchronized (lockBye) { System.out.println("bye"); } } }
这样当线程A访问sayHello时就不会影响线程B访问sayBye了。静态和非静态的区别与前面两种是一样的。
静态同步块:
public class Hello { private static final Object lock = new Object(); public void sayHello(){ synchronized (lock) { System.out.println("hello"); } } }