在实际开发中经常会用到多线程协作来处理问题,锁是处理线程安全不可缺少的机制。在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);
}
} }

可见:

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

 

JAVA锁机制(上)的更多相关文章

  1. 转 : 深入解析Java锁机制

    深入解析Java锁机制 https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw%3D%3D&mid=2247485524&idx=1&s ...

  2. Java 锁机制总结

    锁的种类 独享锁 VS 共享锁 独享锁:锁只能被一个线程持有(synchronized) 共享锁:锁可以被多个程序所持有(读写锁) 乐观锁 VS 悲观锁 乐观锁:每次去拿数据的时候都乐观地认为别人不会 ...

  3. Java锁机制深入理解

    Java锁机制 背景知识 指令流水线 ​ CPU的基本工作是执行存储的指令序列,即程序.程序的执行过程实际上是不断地取出指令.分析指令.执行指令的过程. ​ 几乎所有的冯•诺伊曼型计算机的CPU,其工 ...

  4. java锁机制的面试题

    java锁机制的面试题 1.ABA问题 2.CAS乐观锁 3.synchronize实现原理 4.synchronize与lock的区别 5.volatile实现原理 6.乐观锁的业务场景及实现方式 ...

  5. java锁机制

    2.4 锁机制        临界区是指,使用同一个锁控制的同一段代码区或多段代码区之间,在同一时间内最多只能有一个线程在执行操作.这个概念与传统的临界区有略微的差别,这里不想强调这些概念上的差别,临 ...

  6. Java锁机制了解一下

    前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 只有光头才能变强! 本文章主要讲的是Java多线程加锁机制,有两种: Synchro ...

  7. JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,

    如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...

  8. java 锁机制(synchronized 与 Lock)

    在java中,解决同步问题,很多时候都会使用到synchronized和Lock,这两者都是在多线程并发时候常使用的锁机制. synchronized是java中的一个关键字,也就是说是java内置的 ...

  9. 【面试专栏】JAVA锁机制

    1. 悲观锁 / 乐观锁   在Java和数据库中都存在悲观锁和乐观锁的应用.Mysql锁机制中的悲观锁和乐观锁请查看:   Mysql锁机制--悲观锁和乐观锁   悲观锁:在获得数据时先加锁,只到数 ...

随机推荐

  1. CSS Spritec下载,精灵图,雪碧图,初探之原理、使用

    CSS Spritec下载,精灵图,雪碧图,初探之原理.使用 关于CSS Sprite CSSSprites在国内很多人叫css精灵雪碧图,是一种网页图片应用处理方式.它允许你将一个页面涉及到的所有零 ...

  2. SQL Fundamentals:替代变量(&,&&)以及DEFINE,UNDEFINE,ACCEPT指令

    替代变量 利用替代变量可以实现数据操作的交互性.替代变量的操作类似于键盘输入操作. 所谓的替代变量,指的就是在进行查询或更新操作时,某些数据是由用户所输入的,而这些数据前可以使用“&”标记. ...

  3. 使用CXF做webservice整合现有项目的例子

    从网上看了很多CXF的资料,大部分都是单独的作为一个webservice项目,对于在现有的spring项目上提供webservice服务的例子基本没有找到. 我做的这个例子是介绍怎么把cxf整合到现有 ...

  4. python面向对象(类和对象及三大特性)

    类和对象是什么 创建类 新式类 和 经典类 面向对象三大特性 继承 封装 多态   面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

  5. php版本管理工具composer安装及使用

    类似于web前端有gulp,webpack,grunt.php也有专门的包安装管理和安装工具,即composer. composer官网:https://getcomposer.org      中文 ...

  6. CSS之Flex 布局:语法篇

    网页布局(layout)是 CSS 的一个重点应用. ​ 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如 ...

  7. python 类 __call__

    __call__ 对象后面加括号,触发执行. 即:对象() 或者 类()() class dog(object): def __init__(self,name): self.name = name ...

  8. git-【二】本地git操作提交、版本回退

    一.创建版本库,提交文件 什么是版本库?版本库又名仓库,英文名repository,你可以简单的理解一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改,删除,Git都能跟踪,以便任 ...

  9. 表单(上)EasyUI Form 表单、EasyUI Validatebox 验证框、EasyUI Combobox 组合框、EasyUI Combo 组合、EasyUI Combotree 组合树

    EasyUI Form 表单 通过 $.fn.form.defaults 重写默认的 defaults. 表单(form)提供多种方法来执行带有表单字段的动作,比如 ajax 提交.加载.清除,等等. ...

  10. jQuery实现节点克隆、替换和互换

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...