在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. C# Notes

    Token Based Authentication Attributes Tutorial - Conditional - Obsolete Covariance and Contravarianc ...

  2. CNDS账号密码

    您购买的CSDN 100下载积分 发货如下:CSDN账号:masunwei0961CSDN密码:sangsang3邮箱:lao42981894zh@163.com邮箱密码:songsong3

  3. [hadoop读书笔记] Hadoop下各技术应用场景

    1.数据采集 对于数据采集主要分为三类,即结构化数据库采集,日志和文件采集,网页采集. 对于结构化数据库,采用Sqoop是合适的,可以实现结构化数据库中数据并行批量入库到hdfs存储.对于网页采集,前 ...

  4. FPGA中的时序分析(二)

    使用Timequest 笔者对Altera较熟悉,这里以quartus ii中的timequest作为讲解. Timequest分析时序的核心,也就是在于延迟因数的计算.那么建立约束文件,去告诉tim ...

  5. 使用VS2012生成DLL文件(1)

    文章转载自:1. http://blog.sina.com.cn/s/blog_45bcb4c3010140b3.html 一:生成DLL 1:创建DLL工程 文件->新建->项目-> ...

  6. 【转】android如何实现开机自动启动Service或app

    1.今天我们主要来探讨android怎么让一个service开机自动启动功能的实现.Android手机在启动的过程中会触发一个Standard Broadcast Action,名字叫android. ...

  7. PHP递归算法的简单实例

    递归函数为自调用函数,在函数体内直接或直接自个调用自个,但需求设置自调用的条件,若满意条件,则调用函数自身,若不满意则停止本函数的自调用,然后把目前流程的主控权交回给上一层函数来履行,也许这么给我们解 ...

  8. mysql limit分页查询效率

    对于有大数据量的mysql表来说,使用LIMIT分页存在很严重的性能问题. 查询从第1000000之后的30条记录: SQL代码1:平均用时6.6秒 SELECT * FROM `cdb_posts` ...

  9. 嵌入式开发之hi3519---i2c EEPROM

    http://pdf1.alldatasheetcn.com/datasheet-pdf/view/163283/MICROCHIP/24LC024.html http://www.elecfans. ...

  10. 在js中 把 json对象转化为String对象的方法

    方法1: 使用js的扩展方法 ** * json对象转字符串形式 */ function json2str(o) { var arr = []; var fmt = function(s) { if ...