Java并发编程:Lock

synchronized是java中的一个关键字,也就是说是Java语言内置的特性。那么为什么会出现Lock呢?

  如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁会有三种情况:

  1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;

  2)线程执行发生异常,此时JVM会让线程自动释放锁。

  3)这个主要是在等待唤醒机制里面的wait()方法,//在等待的时候立即释放锁,方便其他的线程使用锁。而且被唤醒时,就在此处唤醒,

  那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。因此我们需要不论程序的代码块执行的如何最终都将锁对象进行释放,方便其他线程的执行。(此处后面有一个简单的demo起始就是将锁对象人工的释放而且是在finally里面的执行)

   虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,同时为了更好地释放锁。
  为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。

  另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。

  总结一下,也就是说Lock提供了比synchronized更多的功能。但是要注意以下几点:

  1)Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;

2)synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

3)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,

但是ReetrantLock的性能能维持常态;一、首先给出一个简单的自锁案例,主要是用于体会自锁的发生即可//------------------------------------------------代码的分割线//首先给出一个死锁的案例第一个类是:MyLock
 
1 public class MyLock {
2     // 创建两把锁对象
3     public static final Object objA = new Object();
4     public static final Object objB = new Object();
5 }

// 发生死锁的线程

 1 public class DieLock extends Thread {
 2
 3     private boolean flag;
 4
 5     public DieLock(boolean flag) {
 6         this.flag = flag;
 7     }
 8
 9     @Override
10     public void run() {
11         if (flag) {
12             synchronized (MyLock.objA) {
13                 System.out.println("if objA");
14                 synchronized (MyLock.objB) {
15                     System.out.println("if objB");
16                 }
17             }
18         } else {
19             synchronized (MyLock.objB) {
20                 System.out.println("else objB");
21                 synchronized (MyLock.objA) {
22                     System.out.println("else objA");
23                 }
24             }
25         }
26     }
27 }

//死锁的测试demo

 1 /*
 2  * 同步的弊端:
 3  *         A:效率低
 4  *         B:容易产生死锁
 5  *
 6  * 死锁:
 7  *         两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
 8  *
 9  * 举例:
10  *         小明和小强的自行车都有两把锁一人一把钥匙案例。
11  *         正常情况:
12  *             小明: 两把锁的钥匙都有;
13  *             小强: 两把锁的钥匙都有。
14  *         现在:
15  *             小明:有其中一把锁的两把钥匙;
16  *             小强:有另一把锁的两把钥匙。
17  *             结局两个人都不能打开锁。。。。一直等待朔夜起不到自行车
18  */
19 public class DieLockDemo {
20     public static void main(String[] args) {
21         DieLock dl1 = new DieLock(true);
22         DieLock dl2 = new DieLock(false);
23
24         dl1.start();
25         dl2.start();
26     }
27 }

//============================================

二、Lock锁的简单使用
 1 import java.util.concurrent.locks.Lock;
 2 import java.util.concurrent.locks.ReentrantLock;
 3
 4 public class SellTicket implements Runnable {
 5
 6     // 定义票
 7     private int tickets = 100;
 8
 9     // 定义锁对象
10     private Lock lock = new ReentrantLock();
11
12     @Override
13     public void run() {
14         while (true) {
15             try {
16                 // 加锁
17                 lock.lock();
18                 if (tickets > 0) {
19                     try {
20                         Thread.sleep(100);
21                     } catch (InterruptedException e) {
22                         e.printStackTrace();
23                     }
24                     System.out.println(Thread.currentThread().getName()
25                             + "正在出售第" + (tickets--) + "张票");
26                 }
27             } finally {
28                 // 释放锁
29                 lock.unlock();
30             }
31         }
32     }
33
34 }
 下面是测试类
 1 public class RunnableDemo {
 2     public static void main(String[] args) {
 3         SellTicketsRunnable str = new SellTicketsRunnable();
 4
 5         Thread tr1 = new Thread(str, "窗口1");
 6         Thread tr2 = new Thread(str, "窗口2");
 7         Thread tr3 = new Thread(str, "窗口3");
 8
 9         //
10         tr1.start();
11         tr2.start();
12         tr3.start();
13     }
14 }

 
				
时间: 2024-10-29 12:10:57

Java并发编程:Lock的相关文章

Java并发编程--Lock

类结构图 Lock概述 Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作.synchronized方法或代码块的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁.Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock()).一个获取可中断锁

5、Java并发编程:Lock

Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问,那就是Lock. 也许有朋友会问,既然都可以通过synchronized来实现同步访问了,那么为什么还需要提供Lock?这个问题将在下面进行阐述.本文先从synchronized的缺陷讲起,然后再讲述java.util.concurrent.locks包

转: 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)

简单使用Lock锁 Java5中引入了新的锁机制--Java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接口有3个实现它的类:ReentrantLock.ReetrantReadWriteLock.ReadLock和ReetrantReadWriteLock.WriteLock,即重入锁.读锁和写锁.lock必须被显式地创建.锁定和释放,为了可以使用更多的功能,一般用ReentrantLock为其实例化

【多线程】Java并发编程:Lock(转载)

原文链接:http://www.cnblogs.com/dolphin0520/p/3923167.html Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问,那就是Lock. 也许有朋友会问,既然都可以通过synchronized来实现同步访问了,那么为什么还需要提供Lock?这个问题将在下面进行阐述

JAVA 并发编程-线程同步通信技术(Lock和Condition)(十)

在之前的博客中已经介绍过线程同步通信技术<JAVA 并发编程-传统线程同步通信技术(四)>,上篇是使用的synchronized,wait,notify来实现,今天我们使用的是Lock和Condition,下面我们结合两者对比来学习. 简单的Lock锁应用: /** * 简单Lock的应用 * @author hejingyuan * */ public class LockTest { public static void main(String[] args) { new LockTest

Java并发编程:Lock(转)

本文转自:http://www.cnblogs.com/dolphin0520/p/3923167.html Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问,那就是Lock. 也许有朋友会问,既然都可以通过synchronized来实现同步访问了,那么为什么还需要提供Lock?这个问题将在下面进行阐述

Java并发编程深入学习——Lock锁

Lock锁介绍 ??在Java 5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile.Java 5.0 增加了一种新的机制:ReentrantLock.它并不是一种替代内置加锁的方法,而是当内置加锁机制不适用时,作为一种可选择的高级功能. Lock接口 Lock接口位于java.util.concurrent.locks包中,它定义了一组抽象的加锁操作. public interface Lock { //获取锁 void lock(); // 如果当

Java并发编程:Concurrent锁机制解析

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

Java并发编程 Volatile关键字解析

volatile关键字的两层语义 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的. 2)禁止进行指令重排序. 根据volatile的语义,我们可以看到,volatile主要针对的是并发三要素(原子性,可见性和有序性)中的后两者有实际优化作用. 可见性: 线程本身并不直接与主内存进行数据的交互,而是通过线程的工作内存来完成相应的操作.

6、Java并发编程:volatile关键字解析

Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatil