`

Java并发笔记之------锁

    博客分类:
  • JAVA
 
阅读更多
接触过并发的朋友相信对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并发编程实战-基础篇

    在Java并发编程中,数据的封装与访问控制、线程安全性的考量、同步机制的使用是重要的基础概念和技巧。以下是从给出的文件内容中提取出的详细知识点: 1. 数据封装与访问控制:确保内部私有数据不被轻易访问,并且...

    Java并发编程实战-读书笔记

    《Java并发编程实战》个人读书笔记,非常详细: 1 简介 2 线程安全性 3 对象的共享 4 对象的组合 5 基础构建模块 6 任务执行 7 取消与关闭 8 线程池的使用 9 图形用户界面应用程序 10 避免活跃性危险 11 性能与可...

    JAVA并发编程实践-构建执行程序块-学习笔记

    JAVA并发编程实践-构建执行程序块-学习笔记 JAVA并发编程实践是指在JAVA编程语言中,使用多线程、并发编程来实现高效、可靠的程序执行。构建执行程序块是指在并发编程中,使用线程安全的类来管理状态,以确保程序的...

    Java并发编程与高并发解决方案-学习笔记-www.itmuch.com.pdf

    本文将基于文档《Java并发编程与高并发解决方案-学习笔记***.pdf》中提供的内容,来详细阐述并发编程和高并发的基本概念、CPU多级缓存与缓存一致性、以及Java内存模型。 ### 并发与高并发概念 在现代多线程编程中...

    java学习笔记-----给java初学者

    Java学习笔记是专门为Java初学者设计的一套详尽的学习资源,旨在帮助新手快速掌握这门广泛使用的编程语言。这份笔记涵盖了从基础概念到高级特性的全面内容,是学习和复习Java知识的理想工具。 1. **Java简介** ...

    [原]Java并发编程实践-读书笔记

    《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考。以下是对书中关键知识点的总结: 1. **线程和进程的区别** - **线程**:是程序执行的最小单位,一个进程中可以有多个线程,它们共享同一块...

    JAVA并发编程实践-线程池-学习笔记

    Java并发编程实践中的线程池是一个关键的概念,它在多线程编程中扮演着至关重要的角色,有效地管理和调度线程资源,以提高系统的性能和效率。线程池通过复用已存在的线程来减少线程的创建和销毁开销,避免了频繁的上...

    java并发编程实践pdf笔记

    这本书的读书笔记涵盖了多个关键知识点,旨在帮助读者深入理解Java并发编程的核心概念。 1. **线程和进程的区别** - **线程** 是程序执行的最小单位,一个进程中可以有多个线程同时执行,共享同一块内存空间,通信...

    JAVA并发编程实践-线程安全-学习笔记

    在Java并发编程中,线程安全是一个至关重要的概念,它涉及到多线程环境下对共享数据的正确管理和访问。线程安全意味着当多个线程同时访问一个对象或数据时,对象的状态能够保持一致性和完整性,不会因为并发导致数据...

    Java并发编程与高并发解决方案-学习笔记

    ### Java并发编程与高并发解决方案知识点总结 #### 一、并发与高并发基本概念 ##### 1.1 并发 - **定义**: 指一个程序在同一时刻拥有两个或更多的线程,这些线程可以在单核或多核处理器上运行。 - **单核处理器上...

    Java笔记---李兴华

    Java是一种高级编程语言,自1995年由Sun Microsystems公司发布以来,迅速成为全球最受欢迎的编程语言之一。Java的设计目标是简单、面向对象、健壮、安全、独立于硬件平台、高性能、可移植性强。 ##### 历史沿革 - ...

    JAVA并发编程实践-线程执行-学习笔记

    总的来说,Java并发编程实践中的任务执行是一个涉及线程调度、线程池管理、任务生命周期控制、结果处理等多个方面的复杂主题。理解和掌握这些概念和技术,能够帮助开发者编写出更加高效、可靠的并发程序。

    JAVA学习经典笔记-----2

    7. **多线程:** Java内置对多线程的支持,简化了并发程序的开发。 #### 三、Java开发环境配置 1. **Linux环境:** - 配置`JAVA_HOME`: 设置为安装Java的目录路径。 - 配置`PATH`: 添加`$JAVA_HOME/bin`到路径...

    Java并发实践-学习笔记

    1. **Java并发基础**:首先,笔记可能会介绍Java并发的基础概念,包括线程的创建(通过`Thread`类或实现`Runnable`接口)、线程的状态(新建、运行、阻塞、等待、死亡)以及线程的生命周期。 2. **同步机制**:Java...

    Java并发编程与高并发解决方案笔记-基础篇.docx

    Java并发编程与高并发解决方案是开发高性能应用的关键技术。在基础篇中,主要涉及以下几个重要知识点: 1. **并发编程基础** - **并发**:并发是指在一个时间段内,多个线程交替执行,使得系统看起来像是同时处理...

    java高并发笔记pdf

    java高并发笔记pdf

    实战Java高并发程序设计-试读

    《实战Java高并发程序设计》是一本专注于Java并发编程实践的书籍,试读版提供了前两章的内容,为读者提供了一个初步了解并发编程基础的窗口。在Java领域,并发编程是构建高性能、高效率系统的关键技术,对于软件开发...

    java笔记资源-java语言教程

    该资源为java笔记资源-java语言教程: java io、java 并发、java 基础、java 容器、java 虚拟机

    Java并发编程与高并发解决方案-学习笔记-www.itmuch.com.rar

    java并发编程与并发解决方案是自己多年开发和学习的笔记,有助于(ˇˍˇ) 想~进一步提高的java开发工程师或架构师深入的学习java架构并发处理。同时,它也是 在实际工作中多年高并发解决方案和经验的总结

Global site tag (gtag.js) - Google Analytics