接触过并发的朋友相信对java的锁都不陌生,Java大体可以分为两种锁,隐式锁(内置锁)和显示锁;
OK,什么是内置锁?
很简单,就是我们经常写的同步块--synchronized。
内置锁使用比较简单,再方法上加入synchronized关键字或者在需要调用的地方添加synchronized(Obj){}块即可;
这里主要说一下显示锁:
OK,什么是显示锁?
很简单,通过一个显示的对象,来手动开启和关闭一个锁。Java util的concurrent包下面有一个locks包,包下有一个lock接口,该接口就是实现显示锁的底层类,ReentrantLock类就是最常用的显示锁。
为什么要显示锁?
优点:显示锁可以使你的代码更加灵活,提供锁可等待、可中断、可重入、公平性策略等机制;在性能方面,jdk5显示锁的性能远远大于内置锁,jdk6中也比内置锁高一些,6中对内置锁做了优化;
缺点:显示锁使用的危险性比内置锁要高,比如如果你忘记在finally块中释放锁,程序可以正常运行,但是,这是一个定时炸&弹,一旦爆发,不可控的结果很可怖!另,因为内置锁是在方法描述中添加的关键字,所以,当线程在执行的时候,在线程转储中能看到哪些调用栈帧中获得了哪些锁,非常有利于调试,而显示锁是一个对象,并没有办法看到哪些调用栈帧中获得了哪些锁。
显示锁怎么用?
显示锁有以下几种:ReentrantLock(保守锁,又有叫互斥锁)、RentrankReadWriteLock(读写锁)
1、ReentrantLock示例:
class Operations { // 创建一个显示锁非公平策略显示锁 final ReentrantLock rwLock = new ReentrantLock(); @SuppressWarnings("static-access") public void exec(long waitTime) { // 获得锁 rwLock.lock(); try { System.out.println(String.format( "Operation - doRead() - I am [%s] read now ", Thread .currentThread().getName())); Thread.currentThread().sleep(waitTime); System.out.println(String.format( "Operation - doRead() - I am [%s] read OK.%s", Thread .currentThread().getName(), waitTime)); } catch (Exception e) { e.printStackTrace(); } finally { // 释放锁 rwLock.unlock(); } } }
public static void main(String[] args) { final Operations op = new Operations(); // 调用线程1,获得锁后,停止1分钟 Thread r1 = new Thread(new Runnable() { @Override public void run() { op.exec(10000L); } }); Thread r2 = new Thread(new Runnable() { @Override public void run() { op.exec(20000L); } }); r1.start(); r2.start(); }
看Operations类,显示的使用一定是和try{}catch(){}finally{}一起使用,在finally中一定要释放锁,当调用Reentrant.lock方法后,他会判断计数是否为零,为零则认为对象没有被锁定,计数+1,调用unlock方法后,同理计数-1,如果为0,则释放锁,别的线程可获得该锁。注意,该锁可以被重入,同一个线程可以递归的获取锁!此锁最多支持同一个线程发起的 2147483648 个递归锁。试图超过此限制会导致由锁方法抛出的Error。上面代码输出:
Operation - doRead() - I am [Thread-0] read now
Operation - doRead() - I am [Thread-0] read OK.10000
Operation - doRead() - I am [Thread-1] read now
Operation - doRead() - I am [Thread-1] read OK.20000
OK,上面是最简单的使用,那么,当有一个线程A在持有锁的时候,又有10个线程在等待锁释放状态,这时候A释放了锁,那么,10个线程是先调用哪个?
上面代码是非公平的策略,即,让等待的10个线程抢锁,谁抢到归谁!如何配置公平策略?在显示锁的构造函数里面,有一个boolean参数,默认false(非公平),如果设置为true则为公平策略,即:哪个等待的时间最长,就优先让哪个线程获得锁。
总结:Reentrant实现了一种最标准的互斥锁,每次仅允许一个线程持有锁,但是很多情况下,对于一个公共的内存对象,你可能需要允许多个线程同时去读,仅一个线程去写,这时候就需要用到读-写锁
2、RentrankReadWriteLock
说明:
一个资源可以被多个读操作访问,或者只能被一个写操作访问,并且读、写操作不能同时存在。
示例:
class Operation { // 定义一个读写锁 final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); // 定义一个读锁 final Lock r = rwLock.readLock(); // 定义一个写锁 final Lock w = rwLock.writeLock(); @SuppressWarnings("static-access") public void doRead(long waitTime) { // 获得读锁 r.lock(); try { System.out.println(String.format( "Operation - doRead() - I am [%s] read now ", Thread .currentThread().getName())); // 持有读锁的状态下休眠 Thread.currentThread().sleep(waitTime); System.out.println(String.format( "Operation - doRead() - I am [%s] read OK.%s", Thread .currentThread().getName(), waitTime)); } catch (Exception e) { e.printStackTrace(); } finally { // 释放锁 r.unlock(); } } public void doWrite() { // 获得一个写锁 w.lock(); try { System.out.println(String.format( "Operation - doRead() - I am [%s] wirte now ", Thread .currentThread().getName())); } finally { // 释放一个写锁 w.unlock(); } } }
public class ReadWriteLockMain { public static void main(String[] args) { final Operation op = new Operation(); // 读线程1 休眠10s Thread r1 = new Thread(new Runnable() { @Override public void run() { op.doRead(10000L); } }); // 读线程2 休眠20s Thread r2 = new Thread(new Runnable() { @Override public void run() { op.doRead(20000L); } }); // 读线程3 休眠30s Thread r3 = new Thread(new Runnable() { @Override public void run() { op.doRead(30000L); } }); // 写操作线程 Thread w1 = new Thread(new Runnable() { @Override public void run() { op.doWrite(); } }); r1.start(); r2.start(); r3.start(); w1.start(); } }
在操作中,线程r1,r2,r3同时获得读锁,r1休眠10s后释放,r2休眠20s后释放,r3休眠30s释放,w1获取读锁;输出中,r1、r2、r3全部同时打印结果,当全部释放后,w1才能获得锁;
Operation - doRead() - I am [Thread-0] read now
Operation - doRead() - I am [Thread-1] read now
Operation - doRead() - I am [Thread-2] read now
Operation - doRead() - I am [Thread-0] read OK.10000
Operation - doRead() - I am [Thread-1] read OK.20000
Operation - doRead() - I am [Thread-2] read OK.30000
Operation - doRead() - I am [Thread-3] wirte now
相关推荐
在Java并发编程中,数据的封装与访问控制、线程安全性的考量、同步机制的使用是重要的基础概念和技巧。以下是从给出的文件内容中提取出的详细知识点: 1. 数据封装与访问控制:确保内部私有数据不被轻易访问,并且...
《Java并发编程实战》个人读书笔记,非常详细: 1 简介 2 线程安全性 3 对象的共享 4 对象的组合 5 基础构建模块 6 任务执行 7 取消与关闭 8 线程池的使用 9 图形用户界面应用程序 10 避免活跃性危险 11 性能与可...
JAVA并发编程实践-构建执行程序块-学习笔记 JAVA并发编程实践是指在JAVA编程语言中,使用多线程、并发编程来实现高效、可靠的程序执行。构建执行程序块是指在并发编程中,使用线程安全的类来管理状态,以确保程序的...
本文将基于文档《Java并发编程与高并发解决方案-学习笔记***.pdf》中提供的内容,来详细阐述并发编程和高并发的基本概念、CPU多级缓存与缓存一致性、以及Java内存模型。 ### 并发与高并发概念 在现代多线程编程中...
Java学习笔记是专门为Java初学者设计的一套详尽的学习资源,旨在帮助新手快速掌握这门广泛使用的编程语言。这份笔记涵盖了从基础概念到高级特性的全面内容,是学习和复习Java知识的理想工具。 1. **Java简介** ...
《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考。以下是对书中关键知识点的总结: 1. **线程和进程的区别** - **线程**:是程序执行的最小单位,一个进程中可以有多个线程,它们共享同一块...
Java并发编程实践中的线程池是一个关键的概念,它在多线程编程中扮演着至关重要的角色,有效地管理和调度线程资源,以提高系统的性能和效率。线程池通过复用已存在的线程来减少线程的创建和销毁开销,避免了频繁的上...
这本书的读书笔记涵盖了多个关键知识点,旨在帮助读者深入理解Java并发编程的核心概念。 1. **线程和进程的区别** - **线程** 是程序执行的最小单位,一个进程中可以有多个线程同时执行,共享同一块内存空间,通信...
在Java并发编程中,线程安全是一个至关重要的概念,它涉及到多线程环境下对共享数据的正确管理和访问。线程安全意味着当多个线程同时访问一个对象或数据时,对象的状态能够保持一致性和完整性,不会因为并发导致数据...
### Java并发编程与高并发解决方案知识点总结 #### 一、并发与高并发基本概念 ##### 1.1 并发 - **定义**: 指一个程序在同一时刻拥有两个或更多的线程,这些线程可以在单核或多核处理器上运行。 - **单核处理器上...
Java是一种高级编程语言,自1995年由Sun Microsystems公司发布以来,迅速成为全球最受欢迎的编程语言之一。Java的设计目标是简单、面向对象、健壮、安全、独立于硬件平台、高性能、可移植性强。 ##### 历史沿革 - ...
总的来说,Java并发编程实践中的任务执行是一个涉及线程调度、线程池管理、任务生命周期控制、结果处理等多个方面的复杂主题。理解和掌握这些概念和技术,能够帮助开发者编写出更加高效、可靠的并发程序。
7. **多线程:** Java内置对多线程的支持,简化了并发程序的开发。 #### 三、Java开发环境配置 1. **Linux环境:** - 配置`JAVA_HOME`: 设置为安装Java的目录路径。 - 配置`PATH`: 添加`$JAVA_HOME/bin`到路径...
1. **Java并发基础**:首先,笔记可能会介绍Java并发的基础概念,包括线程的创建(通过`Thread`类或实现`Runnable`接口)、线程的状态(新建、运行、阻塞、等待、死亡)以及线程的生命周期。 2. **同步机制**:Java...
Java并发编程与高并发解决方案是开发高性能应用的关键技术。在基础篇中,主要涉及以下几个重要知识点: 1. **并发编程基础** - **并发**:并发是指在一个时间段内,多个线程交替执行,使得系统看起来像是同时处理...
java高并发笔记pdf
《实战Java高并发程序设计》是一本专注于Java并发编程实践的书籍,试读版提供了前两章的内容,为读者提供了一个初步了解并发编程基础的窗口。在Java领域,并发编程是构建高性能、高效率系统的关键技术,对于软件开发...
该资源为java笔记资源-java语言教程: java io、java 并发、java 基础、java 容器、java 虚拟机
java并发编程与并发解决方案是自己多年开发和学习的笔记,有助于(ˇˍˇ) 想~进一步提高的java开发工程师或架构师深入的学习java架构并发处理。同时,它也是 在实际工作中多年高并发解决方案和经验的总结