在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法。

因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识。

java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,知道线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。

1、对象锁的synchronized修饰方法和代码块:

  1. public class TestSynchronized
  2. {
  3. public void test1()
  4. {
  5. synchronized(this)
  6. {
  7. int i = 5;
  8. while( i-- > 0)
  9. {
  10. System.out.println(Thread.currentThread().getName() + " : " + i);
  11. try
  12. {
  13. Thread.sleep(500);
  14. }
  15. catch (InterruptedException ie)
  16. {
  17. }
  18. }
  19. }
  20. }
  21. public synchronized void test2()
  22. {
  23. int i = 5;
  24. while( i-- > 0)
  25. {
  26. System.out.println(Thread.currentThread().getName() + " : " + i);
  27. try
  28. {
  29. Thread.sleep(500);
  30. }
  31. catch (InterruptedException ie)
  32. {
  33. }
  34. }
  35. }
  36. public static void main(String[] args)
  37. {
  38. final TestSynchronized myt2 = new TestSynchronized();
  39. Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );
  40. Thread test2 = new Thread(  new Runnable() {  public void run() { myt2.test2();   }  }, "test2"  );
  41. test1.start();;
  42. test2.start();
  43. //         TestRunnable tr=new TestRunnable();
  44. //         Thread test3=new Thread(tr);
  45. //         test3.start();
  46. }
  47. }

上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象,当然,如果需要同步其他对象实例,也不可传入其他对象的实例;第二个方法是修饰方法的方式进行同步。因为第一个同步代码块传入的this,所以两个同步代码所需要获得的对象锁都是同一个对象锁,下面main方法时分别开启两个线程,分别调用test1和test2方法,那么两个线程都需要获得该对象锁,另一个线程必须等待。

2、类锁的修饰(静态)方法和代码块:

  1. public class TestSynchronized
  2. {
  3. public void test1()
  4. {
  5. synchronized(TestSynchronized.class)
  6. {
  7. int i = 5;
  8. while( i-- > 0)
  9. {
  10. System.out.println(Thread.currentThread().getName() + " : " + i);
  11. try
  12. {
  13. Thread.sleep(500);
  14. }
  15. catch (InterruptedException ie)
  16. {
  17. }
  18. }
  19. }
  20. }
  21. public static synchronized void test2()
  22. {
  23. int i = 5;
  24. while( i-- > 0)
  25. {
  26. System.out.println(Thread.currentThread().getName() + " : " + i);
  27. try
  28. {
  29. Thread.sleep(500);
  30. }
  31. catch (InterruptedException ie)
  32. {
  33. }
  34. }
  35. }
  36. public static void main(String[] args)
  37. {
  38. final TestSynchronized myt2 = new TestSynchronized();
  39. Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );
  40. Thread test2 = new Thread(  new Runnable() {  public void run() { TestSynchronized.test2();   }  }, "test2"  );
  41. test1.start();
  42. test2.start();
  43. //         TestRunnable tr=new TestRunnable();
  44. //         Thread test3=new Thread(tr);
  45. //         test3.start();
  46. }
  47. }

类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。那么两个线程都需要获得该对象锁,另一个线程必须等待。

3、synchronized同时修饰静态和非静态方法:

  1. public class TestSynchronized
  2. {
  3. public synchronized void test1()
  4. {
  5. int i = 5;
  6. while( i-- > 0)
  7. {
  8. System.out.println(Thread.currentThread().getName() + " : " + i);
  9. try
  10. {
  11. Thread.sleep(500);
  12. }
  13. catch (InterruptedException ie)
  14. {
  15. }
  16. }
  17. }
  18. public static synchronized void test2()
  19. {
  20. int i = 5;
  21. while( i-- > 0)
  22. {
  23. System.out.println(Thread.currentThread().getName() + " : " + i);
  24. try
  25. {
  26. Thread.sleep(500);
  27. }
  28. catch (InterruptedException ie)
  29. {
  30. }
  31. }
  32. }
  33. public static void main(String[] args)
  34. {
  35. final TestSynchronized myt2 = new TestSynchronized();
  36. Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );
  37. Thread test2 = new Thread(  new Runnable() {  public void run() { TestSynchronized.test2();   }  }, "test2"  );
  38. test1.start();
  39. test2.start();
  40. //         TestRunnable tr=new TestRunnable();
  41. //         Thread test3=new Thread(tr);
  42. //         test3.start();
  43. }
  44. }

上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。

到这里,对synchronized的用法已经有了一定的了解。这时有一个疑问,既然有了synchronized修饰方法的同步方式,为什么还需要synchronized修饰同步代码块的方式呢?而这个问题也是synchronized的缺陷所在

synchronized的缺陷:当某个线程进入同步方法获得对象锁,那么其他线程访问这里对象的同步方法时,必须等待或者阻塞,这对高并发的系统是致命的,这很容易导致系统的崩溃。如果某个线程在同步方法里面发生了死循环,那么它就永远不会释放这个对象锁,那么其他线程就要永远的等待。这是一个致命的问题。

一个类的对象锁和另一个类的对象锁是没有关联的,当一个线程获得A类的对象锁时,它同时也可以获得B类的对象锁。

java的对象锁和类锁的更多相关文章

  1. Java锁Synchronized,对象锁和类锁举例

    Java的锁分为对象锁和类锁. 1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内针对该对象的操作只能有一个线程得到执行.另一个线程必须 ...

  2. Java锁Synchronized对象锁和类锁区别

    java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁.获得内置锁的唯一途径就是进入这个锁的保 ...

  3. Java对象锁和类锁全面解析(多线程synchronized关键字)

    最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚锁的概念.最近也是遇到一些问题,不搞清楚锁的概念,很容易碰壁,甚至有些时候自己连用没 ...

  4. java 对象锁和类锁的区别(转)

    java 对象锁和类锁的区别   转自; ) ); ; ) ); 上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象,当然,如果需要同步其他对象实例,也不可 ...

  5. 【Thread】java线程之对象锁、类锁、线程安全

    说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来 ...

  6. java线程同步以及对象锁和类锁解析(多线程synchronized关键字)

    一.关于线程安全 1.是什么决定的线程安全问题? 线程安全问题基本是由全局变量及静态变量引起的. 若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线 ...

  7. Java 中对象锁和类锁的区别? 关键字 Synchronized的用法?

    一  对象锁和类锁的关系 /* * 对象锁和[类锁] 全局锁的关系? 对象锁是用于对象实例方法,或者一个对象实例上的 this 类锁是用于类的静态方法或者一个类的class对象上的. Ag.class ...

  8. java的同步方法和同步代码块,对象锁,类锁区别

    /** * @author admin * @date 2018/1/12 9:48 * 作用在同一个实例对象上讨论 * synchronized同步方法的测试 * 两个线程,一个线程调用synchr ...

  9. Synchronized方法锁、对象锁、类锁区别

    synchronized,这个东西我们一般称之为”同步锁“,他在修饰代码块的时候需要传入一个引用对象作为“锁”的对象. 在修饰方法的时候,默认是当前对象作为锁的对象 在修饰类时,默认是当前类的Clas ...

随机推荐

  1. android 代码混淆模板

    #指定代码的压缩级别 -optimizationpasses #包明不混合大小写 -dontusemixedcaseclassnames #不去忽略非公共的库类 -dontskipnonpublicl ...

  2. 关于Unity中的光照(四)

    渲染路径和颜色空间 1:Unity光影效果可以通过设置 渲染路径和颜色空间;2: 渲染路径: 光照到物体表面,物体着色的时候,算上光的颜色的时候有这么几种光照的着色方式,计算着色的方式 forward ...

  3. 解决连锁零售行业IT运维管理四大困境

    解决连锁零售行业IT运维管理四大困境   中国近年来,连锁零售行业进入了行业的发展高潮,迅速崛起一批大型连锁业态.而随着IT技术的不断进步,连锁零售企业已经步入IT信息化快速发展的重要阶段:在面对激烈 ...

  4. 第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码

    第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码 打码接口文件 # -*- coding: cp936 -*- import sys import os ...

  5. linux 日志查询

    tail -n 400 logname | grep "AAA" grep 简单使用 1.把要查询的行写到文本里面去: grep WXCP IC.NotifyIndexServer ...

  6. EF5+MVC4系列(2) EF5报错 无法确定“XXX”关系的主体端。添加的多个实体可能主键相同

    情景:用户表和订单表是一对多的关系,即 一个 Userinfo  对应对应有 多个 Order表   如果我在EF中,先创建一个用户,然后创建3个订单,然后关联这1个用户和3个订单的关系,毫无问题. ...

  7. Tomcat5内存简单优化

    tomcat版本:apache-tomcat-5.5.28 解压版tomcat 修改catalina.bat文件,在开头添加如下内容: JAVA_OPTS='-Xms1024m -Xmx2048m - ...

  8. DNS Bind服务配置解析

    DNS域名解析服务(Domain Name System)是用于解析域名与IP地址对应关系的服务,功能上可以实现正向解析与反向解析: 一.DNS服务器工作模式分类: 1.主服务器:在特定区域内具有唯一 ...

  9. utf8_unicode_ci与utf8_general_ci的区别

    From: http://www.chinaz.com/program/2010/0225/107151.shtml 当前,utf8_unicode_ci校对规则仅部分支持Unicode校对规则算法. ...

  10. Spock集成入门

    本文基于SpringBoot 在pom.xml添加Spock依赖 <!-- test --> <dependency> <groupId>org.codehaus. ...