在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. pom.xml设置maven的编码方式

    <build> <defaultGoal>compile</defaultGoal> <plugins> <plugin> <grou ...

  2. WPF ICommandSource Implementations Leak Memory!

    Actually the title of this article should be entitled "How to use WeakEventManager with IComman ...

  3. WinForm窗体继承

    在Windows应用程序中,从现有的窗体继承,查看子窗体的设计视图时,会出现错误: 服务容器中已存在服务 System.Windows.Forms.Design.IEventHandlerServic ...

  4. Qt 程序打包发布总结

    1.  概述 当我们用QT写好了一个软件,要把你的程序分享出去的时候,不可能把编译的目录拷贝给别人去运行.编译好的程序应该是一个主程序,加一些资源文件,再加一些动态链接库,高大上一些的还可以做一个安装 ...

  5. Dijkstra 算法,用于对有权图进行搜索,找出图中两点的最短距离

    Dijkstra 算法,用于对有权图进行搜索,找出图中两点的最短距离,既不是DFS搜索,也不是BFS搜索. 把Dijkstra 算法应用于无权图,或者所有边的权都相等的图,Dijkstra 算法等同于 ...

  6. Mac OS, Mac OSX 与Darwin

    作为收购 NeXT 公司的结果,苹果公司获得了 NeXTSTEP 架构中的 Mach 和 Objective-C 等设计.尽管 NeXTSTEP 本身已经不再发展了,但是其中的组件在 OS X 中获得 ...

  7. 高通 双MIC 设置

    android O中设置双MIC降噪,需要在build.prop添加属性"ro.vendor.audio.sdk.fluencetype"属性. 属性值位于hardware/qco ...

  8. 服务不支持chkconfig的解决

    场景: 写了脚本,想用命令chkconfig加载自启动. chkconfig mongod on 解决方法: mongod 脚本的开头要这样加: #!/bin/bash #chkconfig:345 ...

  9. Spring系列(二):Spring IoC/DI的理解

    这几天重新学习了一下Spring,在网上找了相关的ppt来看,当看到Spring IoC这一章节的时候,先大致浏览了一下内容,有将近50页的内容,内心窃喜~QAQ~,看完这些内容能够对IoC有更深层次 ...

  10. Tomcat 部署一工程时Deploy Location 为什么 是 INVALID

    1.eclipse项目: 在项目的.settings目录下,找到org.eclipse.wst.common.component文件: <?xml version="1.0" ...