Java中使用synchronized关键字来加锁达到同步的目的,synchronized可以在作用在方法上,也可以作用在代码块上。
Java中的每一个对象都可以作为锁,但是基本数量类型不行,如int、float。
synchronized同步非静态方法
非静态同步方法,锁是当前对象实例,如下代码Info类中set()和get()方法都加上synchronized关键字同步,说明Info对象同一实例在同一时刻只能访问set()或get()方法:
- public class Info {
- private String country;
- private String city;
- public synchronized void set(String country, String city) {
- System.out.println("进入设置方法...");
- this.country = country;
- try {
- Thread.sleep(30000);
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- this.city = city;
- System.out.println("完成设置...");
- }
- public synchronized void get() {
- System.out.println("进入读取方法...");
- try {
- Thread.sleep(300);
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("country:" + this.country + "->city:" + this.city);
- }
- public String getCountry() {
- return country;
- }
- public void setCountry(String country) {
- this.country = country;
- }
- public String getCity() {
- return city;
- }
- public void setCity(String city) {
- this.city = city;
- }
- }
synchronized同步静态方法
同步静态方法,锁是当前类的Class对象。如Singleton单例模式在多线程下是不安全的,可以加synchronized关键字来同步,如下代码(此方法只为演示,在大多数情况下不需要同步,此方法性能不好):
- public static synchronized Singleton getInstance() {
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
如下面测试代码,由于静态方法的锁有当前类的,所以每一个getInstance()方法都是同步的,所以性能不高:
- /**
- * Huisou.com Inc.
- * Copyright (c) 2011-2012 All Rights Reserved.
- */
- package thread;
- import java.util.Date;
- /**
- * @description
- *
- * @author chenzehe
- * @email hljuczh@163.com
- * @create 2012-12-4 下午05:33:21
- */
- public class Singleton {
- private static Singleton instance = null;
- private Singleton() {
- }
- public static synchronized Singleton getInstance() {
- System.out.println("...get..." + new Date());
- if (instance == null) {
- instance = new Singleton();
- }
- try {
- Thread.sleep(3000);
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("...ret..." + new Date());
- return instance;
- }
- }
- /**
- * Huisou.com Inc.
- * Copyright (c) 2011-2012 All Rights Reserved.
- */
- package thread;
- import javax.xml.stream.events.StartDocument;
- /**
- * @description
- *
- * @author chenzehe
- * @email hljuczh@163.com
- * @create 2013-1-16 上午09:00:46
- */
- public class SingletonTest {
- public static void main(String[] args) {
- new Thread() {
- public void run() {
- System.out.println("run get...");
- Singleton.getInstance();
- }
- }.start();
- new Thread() {
- public void run() {
- System.out.println("run get2...");
- Singleton.getInstance();
- }
- }.start();
- }
- }
- run get...
- run get2...
- ...get...Wed Jan 16 09:20:12 CST 2013
- ...ret...Wed Jan 16 09:20:15 CST 2013
- ...get...Wed Jan 16 09:20:15 CST 2013
- ...ret...Wed Jan 16 09:20:18 CST 2013
相对好点的多线程单例模式代码如下(懒汉模式):
- public static Singleton getInstance() {
- if (instance == null) {
- synchronized (Singleton.class) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
synchronized关键字不能继承
如果在父类中的某个方法使用了synchronized 关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上 synchronized 关键字才可以。 还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的, 但子类调用了父类的同步方法,因此,子类的方法中调用父类方法后面的代码也就相当于同步了。
接口的定义不能使用 synchronized关键字
构造方法不能使用 synchronized关键字
synchronized关键字可以放在方法访问修饰前面或后面,也可以放在static前面或后面,但是只能放在返回值前面,不能放在返回值后面,如下是正确的:
public synchronized void method();
synchronized public void method();
public static synchronized void method();
public synchronized static void method();
synchronized public static void method();
下面是错误的:
public void synchronized method();
public static void synchronized method();
使用synchronized同步代码块
synchronized块的语法:
- public void method(){
- ......
- synchronized (锁对象){
- ....
- }
- ....
- }
这样synchronized中的代码就会被加锁,锁对象为任意Java对象,对于非静态方法,锁对象一般为当前对象,可能用this关键字表示,对于内 部类,this只表示当前内部类对象,可以使用外部类.this来表示,对于静态方法,锁对象一般使用类.class来表示。
synchronized不能用来同步变量,如下代码是错误的:
public synchronized int i=0;
synchronized深入内容文章:聊聊并发(二)——Java SE1.6中的Synchronized