JAVA synchronized关键字及对象锁通俗理解
2016-12-30 16:44
627 查看
synchronized:Java语言的关键字,当它用来修饰一个方法或者一段代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。然而它的本质是对象锁,即同步的是对象,而不是同步代码。
这里我将分为类跟类实例对象进行演示说明。
运行结果
上面的代码可以看到四个静态方法中,name方法采用同步关键字修饰方法,而address和id方法则采用同步代码块,email方法未同步。区别在于address 同步Object.class这个特殊对象,而id同步Demo.class对象。
四个子线程分别调用四个不同的静态方法,都是打印方法名+当前时间。而name方法在执行完println方法后让其线程sleep 3秒。那么从结果看出name,address,email 方法输出的秒单位时间上是相同的,id则延后了3秒输出,而这3秒则恰恰是name执行打印后的sleep时长,这就表明了Demo类的静态方法synchronized 同步实际上是针对Demo.Class这个特殊对象进行锁同步。
针对类实例对象的测试,我把static 关键字都去除掉,id方法使用this同步代码块。运行结果跟预测的一样:id比name的打印输出延后3秒。
所以证实了开头的定论:无论是类方法还是实例方法,synchronized 同步的是对象,而不是代码,本质是对象锁,针对相同对象才起到同步作用,synchronized 使得线程在获取对象锁的权限下进行有限范围的操作。
这里我将分为类跟类实例对象进行演示说明。
针对Class对象锁
package com.vk; import java.text.SimpleDateFormat; import java.util.Date; public class Demo { static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) { Thread tName = new Thread() { public void run() { name(); }; }; Thread tId = new Thread() { public void run() { id(); }; }; Thread tAddress = new Thread() { public void run() { address(); }; }; Thread tEmail = new Thread() { public void run() { email(); }; }; System.out.println("---------start----------- "+getDate()); tName.start(); tId.start(); tAddress.start(); tEmail.start(); } public synchronized static void name() { System.out.println("Demo sync static method , name " + getDate()); try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void id() { synchronized (Demo.class) { System.out.println("Demo.class sync code block in static method," + " id " + getDate()); } } public static void address() { synchronized (Object.class) { System.out.println("Object.class sync code block in static method, " + "address " + getDate()); } } public static void email() { System.out.println("no sync in static method, email " + getDate()); } static String getDate() { return simpleDateFormat.format(new Date(System.currentTimeMillis())); } }
运行结果
上面的代码可以看到四个静态方法中,name方法采用同步关键字修饰方法,而address和id方法则采用同步代码块,email方法未同步。区别在于address 同步Object.class这个特殊对象,而id同步Demo.class对象。
四个子线程分别调用四个不同的静态方法,都是打印方法名+当前时间。而name方法在执行完println方法后让其线程sleep 3秒。那么从结果看出name,address,email 方法输出的秒单位时间上是相同的,id则延后了3秒输出,而这3秒则恰恰是name执行打印后的sleep时长,这就表明了Demo类的静态方法synchronized 同步实际上是针对Demo.Class这个特殊对象进行锁同步。
针对类实例对象锁
package com.vk; import java.text.SimpleDateFormat; import java.util.Date; public class Demo { static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) { Demo demo = new Demo(); Thread tName = new Thread() { public void run() { demo.name(); }; }; Thread tId = new Thread() { public void run() { demo.id(); }; }; Thread tAddress = new Thread() { public void run() { demo.address(); }; }; Thread tEmail = new Thread() { public void run() { demo.email(); }; }; System.out.println("---------start----------- "+getDate()); tName.start(); tId.start(); tAddress.start(); tEmail.start(); } public synchronized void name() { System.out.println("Demo sync method , name " + getDate()); try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void id() { synchronized (this) { System.out.println("Demo instance sync code block in method," + " id " + getDate()); } } public void address() { synchronized (Demo.class) { System.out.println("Demo.class sync code block in method, " + "address " + getDate()); } } public void email() { System.out.println("no sync in method, email " + getDate()); } static String getDate() { return simpleDateFormat.format(new Date(System.currentTimeMillis())); } }
针对类实例对象的测试,我把static 关键字都去除掉,id方法使用this同步代码块。运行结果跟预测的一样:id比name的打印输出延后3秒。
所以证实了开头的定论:无论是类方法还是实例方法,synchronized 同步的是对象,而不是代码,本质是对象锁,针对相同对象才起到同步作用,synchronized 使得线程在获取对象锁的权限下进行有限范围的操作。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Debian 7.x 安装Oracle JAVA
- springmvc实现url路由功能
- spring boot 配置 druid/** * 配置druid * Created by adam on 4/11/16. */ @Configuration public class D
- api接口rsa加密