java并发包:重入锁与Condition条件

2023-11-15

本文转载至:http://blog.csdn.net/a910626/article/details/51900941

重入锁

  这里介绍一下synchronized、wait、notify方法的替代品(或者说是增强版)-重入锁。重入锁是可以完全替代以上的内容的。并且重入锁的性能是远高于synchronized的,但是jdk6.0开始,jdk对synchronized做了大量的优化,使得两者性能差距不大。

  重入锁使用Java.util.concurrent.locks.ReentrantLock类来实现。它的几个重要方法如下:

lock():获得锁,如果锁已经被占用,则等待。
lockInterruptibly():获得锁,但优先响应中断。
tryLock():尝试获得锁,如果成功,返回true,失败返回false。该方法不等待,立即返回。
tryLock(long time, TimeUnit unit):在给定时间内尝试获得锁。
unLock():释放锁。

注意:把解锁操作lock.unlock()放到finally子句非常重要。这样保证即使在临界区的代码抛出了异常,锁也必须释放,否则,其他线程将永远阻塞.

重入锁简单案例: lock与unLock

package com.mbl;

import java.util.concurrent.locks.ReentrantLock;

public class ReenterLock implements Runnable {
	public static ReentrantLock  lock = new ReentrantLock();
	public static int i = 0; 
	
	public static int getI() {
		return i;
	}

	public static void setI(int i) {
		ReenterLock.i = i;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int j = 0;j < 1000; j++){
			lock.lock();
			try {
                i++;
                System.out.println("i value is:"+i);
            } finally {
                lock.unlock();
            }
		}
	}

}

package com.mbl.main;

import com.mbl.ReenterLock;

public class ReentrantLockDemo {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		ReenterLock rl = new ReenterLock();
		Thread t1 = new Thread(rl);
		Thread t2 = new Thread(rl);
		t1.start();
		t2.start();
//		t1.join();
//		t2.join();
		System.out.println("i result is :"+rl.getI());
	}

}

上述代码使用重入锁保护临界区资源i,确保了多线程对i操作的安全性。从这段代码可以看到,与synchronized相比,重入锁有着显示的操作过程。开发人员必须手动指定何时加锁,何时释放锁。也正因为这样,重入锁对逻辑控制的灵活性要远远好于synchronized,但值得注意的是,在提出临界区时,必须记得释放锁,否则其他线程就没有机会再访问临界区了。

  对于重入锁,同一个线程可以多次获得锁,但是释放锁的时候,也必须释放相同次数。否则会产生异常。

重入锁的中断响应:lockInterruptibly

package com.mbl;

import java.util.concurrent.locks.ReentrantLock;

public class IntLock implements Runnable {
	public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int lock;
    
    /**
     * 控制加锁顺序,方便构造死锁
     *
     * @param lock
     */
    public IntLock(int lock) {
		super();
		this.lock = lock;
	}
    
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try{
			if (lock == 1) {
                lock1.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock2.lockInterruptibly();
            } else {
                lock2.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock1.lockInterruptibly();
            }
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if (lock1.isHeldByCurrentThread()) {
                lock1.unlock();
            }
            if (lock2.isHeldByCurrentThread()) {
                lock2.unlock();
            }
            System.out.println(Thread.currentThread().getId() + ":线程退出");
		}
	}

	

}
package com.mbl.main;

import com.mbl.IntLock;

public class IntLockDemo {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		    IntLock il1 = new IntLock(1);
	        IntLock il2 = new IntLock(2);
	        Thread t1 = new Thread(il1);
	        Thread t2 = new Thread(il2);
	        t1.start();
	        t2.start();
	        Thread.sleep(1000);
	        // 中断其中一个线程
	        //t2.interrupt();
	}

}


锁申请等待限时:lock.tryLock的两个方法

package com.mbl;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TimeLock implements Runnable {
	 public static ReentrantLock lock = new ReentrantLock();

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {            	
            	 System.out.println(Thread.currentThread().getName()+":get lock success");
            	 Thread.sleep(5000);
            } else {
                System.out.println(Thread.currentThread().getName()+":get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
	}
	 
	 
}


公平锁:ReentrantLock的构造函数可以增加一个参数

Condition条件

  如果大家理解了obj.wait和obj.notify方法的话,那么就很容易理解Condition对象了。它和wait和notify方法的作用是大致相同的。但是wait和notify方法是和synchronized关键字合作使用的,而Condition是与重入锁相关联的。通过Condition的newCondition()方法可以生成一个与当前重入锁绑定的Condition实例。利用Condition对象,我们就可以让线程在合适的时间等待,或者在某一个特定的时间得到通知,继续执行。

Condition提供的基本方法如下:

void   await() 
          Causes the current thread to wait until it is signalled or interrupted.
 boolean    await(long time, TimeUnit unit) 
          Causes the current thread to wait until it is signalled or interrupted, or the specified waiting time elapses.
 long   awaitNanos(long nanosTimeout) 
          Causes the current thread to wait until it is signalled or interrupted, or the specified waiting time elapses.
 void   awaitUninterruptibly() 
          Causes the current thread to wait until it is signalled.
 boolean    awaitUntil(Date deadline) 
          Causes the current thread to wait until it is signalled or interrupted, or the specified deadline elapses.
 void   signal() 
          Wakes up one waiting thread.
 void   signalAll() 
          Wakes up all waiting threads


以上方法的具体含义如下:

await() 方法会是当前线程等待,同时释放当前锁,当其他线程中使用signal() 或signalAll() 方法时,线程会重新获得锁并继续执行。或者当线程被中断时,也能跳出等待。这和obj.wait方法很相似。

awaitUninterruptibly() 方法与await() 方法基本相同,只不过它不会在等待过程中响应中断。

signal() 方法用于唤醒一个在等待中的线程,这和obj.notify方法很类似。

简单示例

/**
 * Created by niehongtao on 16/7/8.
 * Condition用法
 */
public class ReenterLockcondition implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();
    public static Condition condition = lock.newCondition();



    @Override
    public void run() {
        lock.lock();
        try {
            condition.await();
            System.out.println("thread is going on");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public static void main(String[] args) throws InterruptedException {
        ReenterLockcondition rlc = new ReenterLockcondition();
        Thread t1 = new Thread(rlc);
        t1.start();
        Thread.sleep(2000);
        // 通知线程继续执行
        lock.lock();
        condition.signal();
        lock.unlock();
    }
}

代码中,听过lock生成一个与之绑定的Condition对象。代码15行要求线程在Condition对象上进行等待。代码32行,由主线程发起通知,告知等待在Condition上的线程可以继续执行了。

  和obj.wait和notify方法一样,当线程使用Condition.await时,要求线程持有相关的重入锁,在Condition.await调用后,这个线程会释放这把锁。同理,在Condition.signal方法调用时,也要求线程先获得相关的锁。在signal方法调用后,系统会从当前Condition对象的等待队列中,唤醒一个线程。一旦线程被唤醒,它会重新尝试获得与之绑定的重入锁,一旦成功获取,就可以继续执行了。因此,在signal方法调用之后,一般需要释放相关的锁,谦让给被唤醒的线程,让他可以继续执行。比如,在本例中,第33行就释放了重入锁,如果省略第24行,那么,虽然已经唤醒了线程t1,但是由于它无法重新获得锁,因而也就无法真正的继续执行。

  在jdk内部,重入锁和Condition对象被广泛的使用,后面讲到的线程安全的容器,他们的内容时候都有重入锁和Condition对象的影子




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java并发包:重入锁与Condition条件 的相关文章

  • Java 终止嵌套for 循环总结

    public class NestedLoopDemo public static void main String args 第一步 构建嵌套for 循环 for int i 0 i lt 10 i for int j 0 j lt 10
  • java并发包:读写锁

    本文转载至 http blog csdn net a910626 article details 51900954 ReadWriteLock是jdk5中提供的读写分离锁 读写分离锁可以有效的帮助减少锁竞争 以提升性能 用锁分离的机制来提升
  • (java基础知识)HashMap排序,Comparator接口详解

    对于List 可以调用Collections工具类的sort 方法 直接进行排序 HashMap 就没这么幸福了 其实 只要了解了Comparator这个接口之后 HashMap的排序也就不难了 无论是根据key 还是根据value排序 这
  • Java线程:线程的交互

    本文转载至 http lavasoft blog 51cto com 62575 99157 线程交互是比较复杂的问题 SCJP要求不很基础 给定一个场景 编写代码来恰当使用等待 通知和通知所有线程 一 线程交互的基础知识 SCJP所要求的
  • (java 功能篇)java 读取Propety配置文件

    java效果代码 源代码 package com rf test import java io IOException import java io InputStream import java util Properties publi
  • java 阻塞模式与非阻塞模式

    TCP IP 阻塞模式与非阻塞模式 java view plain copy print package concurrentTest import java io BufferedReader import java io IOExcep
  • java并发包:概论

    本文转载至 http blog csdn net a910626 article details 51900917 为什么要学习并发 今天和一哥们聊天 聊着聊着聊到钱的方面 当时我就说 全世界60亿人 要是每人给我一块钱那不就发财了啊 哥们
  • Java线程:并发协作-死锁

    本文转载至 http lavasoft blog 51cto com 62575 222074 Java线程 并发协作 死锁 线程发生死锁可能性很小 即使看似可能发生死锁的代码 在运行时发生死锁的可能性也是小之又小 发生死锁的原因一般是两个
  • Java 生成随机数全数字方式

    生成9位随机数字 System out println int Math random 9 1 100000000 生成8位随机数字 System out println int Math random 9 1 10000000 生成6位随
  • Java线程:新特征-有返回值的线程

    本文转载至 http lavasoft blog 51cto com 62575 222082 在Java5之前 线程是没有返回值的 常常为了 有 返回值 破费周折 而且代码很不好写 或者干脆绕过这道坎 走别的路了 现在Java终于有可返回
  • 使用 IO 流 读取 本 地 文 件 (两种方式)

    使用IO 流读取本地文件 public class FileReadWrite public static void main String args FileReader fr null try 1 创建读取文件 fr new FileR
  • 代码质量保障第2讲:单元测试 - 浅谈单元测试

    代码质量保障第2讲 单元测试 浅谈单元测试 本文是代码质量保障第2讲 浅谈单元测试 单元测试 unit testing 是指对软件中的最小可测试单元进行检查和验证 这是基础 所以围绕着单元测试 我从网上搜集和总结了相关的概念 以助你完善体系
  • (java 基础知识) Java 安全套接字--javax.net.ssl

    有关SSL的原理和介绍在网上已经有不少 对于Java下使用keytool生成证书 配置SSL通信的教程也非常多 但如果我们不能够亲自动手做一个SSL Sever和SSL Client 可能就永远也不能深入地理解Java环境下 SSL的通信是
  • (Java 基础知识) Java线程池

    ExecutorService 建立多线程的步骤 1 定义线程类 class Handler implements Runnable 2 建立ExecutorService线程池 ExecutorService executorServic
  • Java线程:线程状态的转换

    本文转载至 http lavasoft blog 51cto com 62575 99153 一 线程状态类型 1 新建状态 New 新创建了一个线程对象 2 就绪状态 Runnable 线程对象创建后 其他线程调用了该对象的start 方
  • java 多线程学习笔记之 线程同步

    在前面我们将了很多关于同步的问题 然而在现实中 需要线程之间的协作 比如说最经典的生产者 消费者模型 当队列满时 生产者需要等待队列有空间才能继续往里面放入商品 而在等待的期间内 生产者必须释放对临界资源 即队列 的占用权 因为生产者如果不
  • Java线程:线程的调度-休眠

    本文转载至 http lavasoft blog 51cto com 62575 221790 Java线程 线程的调度 休眠 Java线程调度是Java多线程的核心 只有良好的调度 才能充分发挥系统的性能 提高程序的执行效率 这里要明确的
  • 线程管理之Thread类相关方法简介

    CurrentThread 静态方法 currentThread 方法可返回代码段正在被那个线程调用的信息 简单案列 打印main 方法 正在被那个线程调用 package com zzg thread import com zzg obj
  • (java 基础知识) Java打印---javax.print

    package com print import java io import javax print import javax print attribute import javax print attribute standard p
  • java并发包:fork/join

    本文转载至 http blog csdn net a910626 article details 51900967 Fork Join框架是Java7提供了的一个用于并行执行任务的框架 是一个把大任务分割成若干个小任务 最终汇总每个小任务结

随机推荐

  • 解决安卓悬浮窗异常:java.lang.IllegalArgumentException

    在开发安卓悬浮窗的过程中有可能会遇到这个异常 java lang IllegalArgumentException View not attached to window manager 原因 如果是在执行android view View
  • 用一个数组实现两个栈(共享栈)

    共享栈 一个数组实现两个栈 第一个栈是开头 第二个栈是结尾 用c语言实现 很简单 两个指针一个数组就够了 上代码 define CRT SECURE NO WARNINGS 1 include
  • Windows中从浏览器启动本地应用程序 Pluggable Protocol

    项目中需要从网页中打开一个本地应用程序 并传递给应用程序启动参数 方法有很多 最简单的一种是通过自定义协议 类似于mailto http https 主流浏览器都支持 只需要在注册表中添加相应内容即可 官方叫做 Pluggable Prot
  • 在CentOS 7中使用BIND部署DNS服务器 - 正向/反向解析

    DNS Domain Name System 域名系统 用于解析域名与IP地址的映射关系 根据主机名 域名 解析对应的IP地址称之为正向解析 根据IP地址解析对应的主机名 域名 称为之反向解析 DNS服务器又分为主服务器 从服务器和缓存服务
  • 进制转换成_10to16

    include math h void 10to16 char 10 char 16 int n n atoi 10 sprintf 16 x n main char 10 20 16 20 printf input 10 jinzhi n
  • QT 去掉标题栏和去掉标题栏后移动窗口

    转自 http www 2cto com kf 201302 191602 html 在用QT编写界面时 去掉标题栏方法比较简单 就一行代码 this gt setWindowFlags Qt FramelessWindowHint 去掉以
  • go 无限极分类实现 返回树状排列数据 或 树状层级数据

    根据从数据表中查询的多条数据得到树状数据 数据表中根据 id 与 pid进行区分上下级 具体实现如下 1 分类排列 Menu 菜单 type Menu struct Id int Pid int CateName string Desc s
  • go 关于redis包的依赖包go.opentelemetry.io/otel下载出现i/o timeout

    通过go get u v github com go redis redis对redis包进行添加 会出现i o timeout的错误 对于该依赖包的解决方法在百度查找不到 但是可以找到相关的网站 https opentelemetry i
  • 中文停用词

    一 数 日 0 1 2 3 4 5 6 7 8 9 lt gt gt gt A Lex exp sub sup
  • 专题详解-5G接入控制(1)

    相关文章会在公众号同步更新 公众号 5G通信大家学 持续更新的相关5G内容都是直接根据3GPP整理 保证更新内容的准确性 避免通过二手 甚至多手的资料 以讹传讹误导网友 最近工作中遇到了一些5G专网接入限制的问题 以前没仔细研究 借着解决这
  • angular路由参数路由跳转

    路由参数及跳转 本节介绍路由参数及跳转相关 准备工作 首先 我们需要将上一节的 CommentService UserService抽离成单独的文件 以便多处使用 ng g s components router study comment
  • Python入门_使用while循环计算1-100之间偶数和

    案例 计算1 100之间所有偶数的和 i 1 定义一个变量sum为0 用来存放和 sum 0 while i lt 100 每次sum和i相加 if i 2 0 sum i i 1 执行完之后 打印sum的值 print 1 100之间偶数
  • Nginx实现反向代理和负载均衡

    Nginx安装 本文章主要介绍下 如何使用Nginx来实现反向代理和负载均衡 Nginx安装和基础知识 可参考我的这篇文章 Nginx安装 Nginx实现反向代理 实现反向代理需要准备两台Nginx服务器 一台Nginx服务器A ip为 1
  • leetcode33. 搜索旋转排序数组

    整数数组 nums 按升序排列 数组中的值 互不相同 在传递给函数之前 nums 在预先未知的某个下标 k 0 lt k lt nums length 上进行了 旋转 使数组变为 nums k nums k 1 nums n 1 nums
  • 【Python编程】如何在 Jupyter Notebook 中切换虚拟环境

    如何在 Jupyter Notebook 中切换虚拟环境 一 操作步骤 1 首先切换到想要在 Jupyter Notebook 里使用的虚拟环境 conda activate 环境名称 2 安装 ipykernel conda instal
  • TCP详解(一)服务和首部介绍

    文章目录 引言 TCP的服务 TCP首部 引言 TCP全称传输控制协议 Transmission Control Protocol 它是一种传输层通信协议 提供了面向连接的 可靠的字节流服务 本文将会简要介绍TCP为应用层提供的服务以及TC
  • node基础之三:http 模块

    1 导入模块 const http require http 2 创建服务 const server http createServer request response gt 获取请求方法 request method 获取请求 url
  • 阿里云1核1G内存1M宽带可以支持多少IP访问量?

    阿里云1核CPU 1G内存 1M公网宽带云服务器够用吗 1M宽带可以支持多少IP的访问量 来说说1M宽带可以跑多少流量及1核1G服务器配置性能 1核 1G 1M宽带配置能跑多少IP 一般来讲 如果图片不多 每天3000PV是没问题的 如果将
  • 优秀的CobaltStrike插件推荐:编程

    优秀的CobaltStrike插件推荐 编程 CobaltStrike是一款功能强大的渗透测试工具 广泛应用于红队行动和网络安全评估 它的灵活性和可扩展性使得开发者可以编写自己的插件来增强其功能 在这篇文章中 我将向你推荐一些好用的Coba
  • java并发包:重入锁与Condition条件

    本文转载至 http blog csdn net a910626 article details 51900941 重入锁 这里介绍一下synchronized wait notify方法的替代品 或者说是增强版 重入锁 重入锁是可以完全替