在实际开发中经常会用到多线程协作来处理问题,锁是处理线程安全不可缺少的机制。在JAVA中可以通过至少三种方式来实现线程锁。

    1.  synchronized修饰符,这种锁机制是虚拟机实现的一种锁。

2. Lock接口的实现类,这种是JAVA程序实现的锁机制。

3. CAS 通过调用底层本地方法CompareAndSet 来实现。

余下内容将结合具体的例子来看看这三种锁机制的不通,以及介绍锁实现原理。

锁机制实现介绍

     在实际业务中,我们为了提高cpu的使用效率,为了提高程序执行效率,引入了多线程,而对于一些共享资源,多线程操作往往会造成线程安全问题,这时候我们往往需要一种机制可以保证多线程访问这些共享资源的时候可以先后访问。锁解决的就是这个问题。我们在访问这些资源时候需要先拿到锁,当访问介绍的时候需要释放锁,拿到锁后,其它线程就阻塞等待,一次保重共享资源多线程访问的安全。

synchronized修饰符

     在虚拟机中有方法栈,对象通过堆形式存储,所有对象可以被多线程共享,synchronized是JAVA虚拟机提供的一种锁机制实现,分方法锁,对象锁,类锁,由于是虚拟机底层实现的锁机制,所以通过synchronized实现的锁机制要比程序自己实现的锁机制更加高效和方便使用。

 方法锁:

1. 未加线程

public class SynchronizedMtdTest {

  public static void main(String[] args) {
System.out.println("主线程开始~");
StringBuffer stringBuffer =new StringBuffer();
new Thread(new Runnable() {
@Override
public void run() {
SynchronizedMtdTest.mtd("pid="+ Thread.currentThread().getId()+",这是一个线程调用方法执行~",stringBuffer); }
}).start();
new Thread(new Runnable() {
@Override
public void run() {
SynchronizedMtdTest.mtd("pid="+ Thread.currentThread().getId()+",这是一个线程调用方法执行~",stringBuffer);
}
}).start();
System.out.println("主线程结束~");
} public static synchronized void mtd(String text,StringBuffer stringBuffer){
try {
stringBuffer.append(text);
Thread.sleep(5000);
stringBuffer.append("\n");
System.out.println(stringBuffer);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }

 结果:

    主线程开始~

主线程结束~
  pid=10,这是一个线程调用方法执行~pid=11,这是一个线程调用方法执行~

pid=10,这是一个线程调用方法执行~pid=11,这是一个线程调用方法执行~

2. 加锁

 

public static synchronized void mtd(String text,StringBuffer stringBuffer){
try {
stringBuffer.append(text);
Thread.sleep(5000);
stringBuffer.append("\n");
System.out.println(stringBuffer);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

结果:

    主线程开始~

     主线程结束~

     pid=10,这是一个线程调用方法执行~

pid=10,这是一个线程调用方法执行~
     pid=11,这是一个线程调用方法执行~

可见在没有加锁的情况下结果是乱的,而且每次执行的循序可能不一样,而加锁后从执行结果可以看出对对象的操作是互斥操作,保证了线程的安全。

  对象锁

   对于方法锁保证了多线程在调用方法时候互斥,而实际中我们方法中不仅有对共享对象操作还有局部对象的操作,未了提高程序的执行效率,JAVA提供了对象锁和类锁实现。

public static void mtd(String text, StringBuffer stringBuffer) {
System.out.println("方法调用开始~");
synchronized (stringBuffer) {
stringBuffer.append(text);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
stringBuffer.append("\n");
System.out.println(stringBuffer); 
} 
System.out.println("方法调用结束~"); }

 结果:   

  方法调用开始~
  方法调用开始~
  主线程结束~
  pid=10,这是一个线程调用方法执行~

  方法调用结束~
  pid=10,这是一个线程调用方法执行~
  pid=11,这是一个线程调用方法执行~

  方法调用结束~

可以看到被加锁的对象在多线程访问的时候,互斥访问。

  假定猜想

         对象锁是保证锁内代码执行互斥?还是只保证对加锁对象做的互斥。做如下调整

public static void mtd(String text, StringBuffer stringBuffer) {
System.out.println("方法调用开始~");
synchronized (stringBuffer) {
System.out.println("-----------1--------");
stringBuffer.append(text);
System.out.println("-----------2--------");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
stringBuffer.append("\n");
System.out.println(stringBuffer);
}
System.out.println("方法调用结束~");
}

  结果:

  主线程开始~
  方法调用开始~
  -----------1--------
  -----------2--------
  主线程结束~
  方法调用开始~
  pid=10,这是一个线程调用方法执行~

  方法调用结束~
  -----------1--------
  -----------2--------
  pid=10,这是一个线程调用方法执行~
  pid=11,这是一个线程调用方法执行~

  方法调用结束~

  类锁

 public static void appendStr(String text) {
synchronized (Object.class) {
stringBuffer.append(text);
try {
System.out.println("-------------");
System.out.println(stringBuffer);
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void printStr() {
synchronized (Object.class) {
System.out.println("-------------");
System.out.println(stringBuffer);
}
} }

可见:

对于对象锁来说,可以理解为在内存有个记录锁机制的地方,所有可以共享这个空间的线程,都可以获取锁和释放锁,而且相同线程可以重复获取锁,但是其它线程在未获得锁的时候需要阻塞等待。而类锁,原理相同,不过可能存放区域不同。

 

最新文章

  1. DISCUZ官方论坛模仿开发日志(二)
  2. day14---html基础
  3. LinearLayout 垂直滚动条
  4. linux 2.6.21版本的内核合法的MAC地址
  5. MyEclipse Blue Edition 6.5 注册码生成程序
  6. NOIP2009 最优贸易
  7. HDU-4647 Another Graph Game 贪心,博弈
  8. 【HDOJ】3315 My Brute
  9. solr的EmbeddedSolrServer原理深入探讨
  10. Ubuntu10.4 install jdk1.6
  11. paip.tree 生成目录树到txt后的折叠查看
  12. MVC从视图传参到Controller几种方式
  13. ActiveMQ in Action(2) - Transport
  14. EhLib DBGridEh组件在Delphi中应用全攻略总结(转)
  15. 前后端分离之vue2.0+webpack2 实战项目 -- webpack介绍
  16. 【PHP】最详细PHP从入门到精通(四)——PHP中的字符串
  17. 如何在ST官网下载STM32固件库
  18. 【BZOJ4002】[JLOI2015]有意义的字符串(数论,矩阵快速幂)
  19. 第五次编程作业-Regularized Linear Regression and Bias v.s. Variance
  20. 章节七、3-ArrayList和LinkedList对比

热门文章

  1. MVC学习之简单的CRUD
  2. CentOS中为新用户添加sudo权限
  3. mongoexport
  4. Django - rest - framework - 上
  5. Dolls---hdu4160(最大匹配)
  6. 通过pd.to_sql()将DataFrame写入Mysql
  7. EOS Dapp开发(1)-基于Docker的开发环境搭建
  8. 关于ML的思考讲座-周zh-11.30日
  9. SCons构建工具使用
  10. Linux命令: grep命令