在实际开发中经常会用到多线程协作来处理问题,锁是处理线程安全不可缺少的机制。在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. 从零打造在线网盘系统之Struts2框架核心功能全解析

    欢迎浏览Java工程师SSH教程从零打造在线网盘系统系列教程,本系列教程将会使用SSH(Struts2+Spring+Hibernate)打造一个在线网盘系统,本系列教程是从零开始,所以会详细以及着重 ...

  2. postgresql----TEMPORARY TABLE和UNLOGGED TABLE

    一.TEMPORARY|TEMP TABLE 会话级或事务级的临时表,临时表在会话结束或事物结束自动删除,任何在临时表上创建的索引也会被自动删除.除非用模式修饰的名字引用,否则现有的同名永久表在临时表 ...

  3. 160226、js常用的验证

    /*** 特殊符号 */ function specialCharacter(carNo){ var st=/^[^/@#$%^&*()—''_()!¥~·..,-<><&g ...

  4. Oracle性能优化之Oracle里的统计信息

    一.什么是统计信息 oracle数据库里的统计信息是如下的一组数据:他们存储在数据字典里,且从多个维度描述了oracle数据库数据对象的详细信息. oracle数据库里的统计信息主要分为以下6种情况: ...

  5. spring boot web服务

    [root@d java]# tree -I target .├── pom.xml└── src ├── main │   ├── java │   │   └── com │   │   └── ...

  6. const V.S readonly

    先上两个例子: ; ; static void Main(string[] args) { Console.WriteLine("A is {0},B is {1}", A, B) ...

  7. git-【七】bug分支

    在开发中,会经常碰到bug问题,那么有了bug就需要修复,在Git中,分支是很强大的,每个bug都可以通过一个临时分支来修复,修复完成后,合并分支,然后将临时的分支删除掉. 比如我在开发中接到一个40 ...

  8. tcp socket http(复制的)

    物理层-- 数据链路层-- 网络层--                       IP协议 传输层--                       TCP协议 会话层-- 表示层和应用层--     ...

  9. Atcoder CADDi 2018 Solution

    C - Product and GCD Solved. 题意: 给出$n个数$的乘积,求$这n个数$的最大的可能是GCD 思路: 分解质因子,那么$每个质因子的贡献就是其质因子个数/ n的乘积$ #i ...

  10. jmeter -xml日志格式中网络时间与服务器时间的区分

    在 LR 中是有一个“网页细分图”的,通过这个图,你可以比较容易的区分哪些请求的响应时间最长,如果响应时间过程,是消耗在server处理的时候,还是消耗在网络传输过程中——也就是所谓的 Server ...