java并发编程之线程同步基础(二)使用锁实现同步
2016-12-19 16:06
495 查看
1:Lock 使用锁实现同步
java提供了同步代码块的另一种机制 它是一种比synchronized关键字更强大更灵活的机制 这个机制基于Lock接口及其实现类支持更灵活的同步快代码结构 使用sychronized关键字时 只能在同一个synchronized块结构中获取和释放控制 Lock接口徐云实现更复杂的临界区结构
相比sychronized关键字 Lock结构提供了更多的功能 其中一个新功能是tryLock方法实现 这个方法视图获取锁 如果锁已经被其他线程获取 它将返回false 并且继续往下执行代码 使用sychronized关键字时 如果现在A试图执行一个同步代码块 而线程B已在执行这个同步代码块 则线程A就会被挂起 知道线程B运行完这个同步代码块 。
Lock接口允许分离读和写操作 运行多个读线程和一个写线程
接下来就实现使用Lock接口和它的实现类ReentrantLock类来创建一个临界区
创建一个打印队列
public class PrintQueue {
//声明一个锁对象 并且初始化
private final Lock queueLock=new ReentrantLock();
public void printJob(){
调用lock方法获取对锁对象的控制
queueLock.lock();
try{
Long duration=(long) (Math.random()*10000);
System.out.println(Thread.currentThread().getName()+":PrintQueue: Printing a Job during "+(duration/1000)+" seconds");
Thread.sleep(duration);
}catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}finally{
//t通过unlock方法释放对锁对象的控制
queueLock.unlock();
}
}
}
创建打印工作类对象
public class Job implements Runnable {
private PrintQueue printQueue;
public Job(PrintQueue printQueue){
this.printQueue=printQueue;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.printf("%s :Going to ptint a document\n",Thread.currentThread().getName());
printQueue.printJob( );
System.out.printf("%s : The doucument has been printed\n",Thread.currentThread().getName());
}
}
创建主类
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
PrintQueue printQueue=new PrintQueue();
//创建10个打印工作Job对象 并把它作为传入参数创建线程
Thread thread[]=new Thread[10];
for(int i=0;i<10;i++){
thread[i]=new Thread(new Job(printQueue),"Thread"+i);
}
for(int i=0;i<10;i++){
thread[i].start();
}
}
}
工作原理:
这个例子中主要是PrintQueue中的printJob方法 使用锁实现一个临界区 并且保证同一时间只有一个执行线程访问这个临界区 必须创建ReentrantLock对象 在这个临界区的开始 必须通过lock方法获取对锁的控制 当线程A访问这个方法时 如果没有其他线程获取对这个锁的控制 lock方法将让线程A获的锁 并且允许它立刻访问临界区代码 不然其他线程B正在执行这个锁保护的临界区代码 Lock方法将让现在A休眠到线程B执行完临界区的代码 在离开临界区的时候我们必须使用unlock方法来释放它持有的锁
以让其他线程来访问临界区
2:使用读写锁实现同步数据访问
锁机制最大的改进之一就是ReadWriteLock接口和他唯一实现类ReentrantReadWriteLock 这个类有两个锁 一个是读写锁 另外一个是操作锁 使用读操作锁时可以允许多个线程同时访问 但是使用写操作锁时只允许一个线程 在一个现在执行写操作时 其他线程不能够执行读操作下面就实现如何使用ReadWriteLock接口控制对价格对象的访问
创建一个加个信息类
public class PricesInfo {
private double price1;
private double price2;
/**
* 声明读写锁 ReadWriteLock
*/
private ReadWriteLock lock;
public PricesInfo(){
price1=1.0;
price1=2.0;
lock=new ReentrantReadWriteLock();
}
public double getPrice1(){
//使用读锁来获取对这个属性的访问
lock.readLock().lock();
double value=price1;
lock.readLock().unlock();
return value;
}
public double getPrice2(){
lock.readLock().lock();
double value=price2;
lock.readLock().unlock();
return value;
}
//使用写锁来获取对这个属性的访问
public void setPrice1(double price1,double price2){
lock.writeLock().lock();
this.price1=price1;
this.price2=price2;
lock.writeLock().unlock();
}
}
创建读取类 Reader
public class Reader implements Runnable {
private PricesInfo pricesInfo;
public Reader(PricesInfo pricesInfo){
this.pricesInfo=pricesInfo;
}
@Override
public void run() {
// TODO Auto-generated method stub
//读取两个价格值
for(int i=0;i<10;i++){
System.out.printf("%s: Price1: %f\n",Thread.currentThread().getName(),pricesInfo.getPrice1());
System.out.printf("%s: Price 2: %f\n",Thread.currentThread().getName(),pricesInfo.getPrice2());
}
}
}
创建写入类Writer 这个类将修改价格信息
public class Writer implements Runnable {
private PricesInfo pricesInfo;
public Writer(PricesInfo pricesInfo){
this.pricesInfo=pricesInfo;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<3;i++){
System.out.printf("Writer: Attempt to modify the prices.\n");
pricesInfo.setPrice1(Math.random()*10, Math.random()*8);
System.out.printf("Writer: Prices hava been modified.\n");
try{
Thread.sleep(2);
}catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
创建主类
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
PricesInfo pricesInfo=new PricesInfo();
Reader []reader=new Reader[5];
Thread threadsReader[]=new Thread[5];
//创建五个读取类Reader 并把每一个对象作为传入参数创建线程
for(int i=0;i<5;i++){
reader[i]=new Reader(pricesInfo);
threadsReader[i]=new Thread(reader[i]);
}
Writer writer=new Writer(pricesInfo);
Thread threadWriter=new Thread(writer);
for(int i=0;i<5;i++){
threadsReader[i].start();
}
threadWriter.start();
}
}
运行结果如下
Thread-3: Price1: 2.000000
Thread-4: Price1: 2.000000
Writer: Attempt to modify the prices.
Thread-1: Price1: 2.000000
Thread-1: Price 2: 3.420673
Thread-0: Price1: 2.000000
Thread-2: Price1: 2.000000
Thread-0: Price 2: 3.420673
Thread-1: Price1: 1.044452
Thread-1: Price 2: 3.420673
Writer: Prices hava been modified.
Thread-4: Price 2: 0.000000
Thread-3: Price 2: 0.000000
Thread-4: Price1: 1.044452
Thread-4: Price 2: 3.420673
Thread-1: Price1: 1.044452
Thread-0: Price1: 1.044452
Thread-2: Price 2: 3.420673
Thread-0: Price 2: 3.420673
Thread-1: Price 2: 3.420673
Thread-4: Price1: 1.044452
Thread-3: Price1: 1.044452
Thread-4: Price 2: 3.420673
Thread-1: Price1: 1.044452
Thread-0: Price1: 1.044452
Thread-2: Price1: 1.044452
Thread-0: Price 2: 3.420673
Thread-1: Price 2: 3.420673
Thread-1: Price1: 1.044452
Thread-1: Price 2: 3.420673
Thread-4: Price1: 1.044452
Thread-3: Price 2: 3.420673
Thread-4: Price 2: 3.420673
Thread-4: Price1: 1.044452
Thread-1: Price1: 1.044452
Thread-0: Price1: 1.044452
Thread-2: Price 2: 3.420673
Thread-2: Price1: 1.044452
Thread-2: Price 2: 3.420673
Thread-2: Price1: 1.044452
Thread-0: Price 2: 3.420673
Thread-1: Price 2: 3.420673
Thread-4: Price 2: 3.420673
Writer: Attempt to modify the prices.
Thread-3: Price1: 1.044452
Writer: Prices hava been modified.
Thread-4: Price1: 1.044452
Thread-1: Price1: 1.044452
Thread-0: Price1: 1.044452
Thread-2: Price 2: 3.420673
Thread-0: Price 2: 1.312381
Writer: Attempt to modify the prices.
Thread-1: Price 2: 1.312381
Thread-1: Price1: 9.619444
Thread-4: Price 2: 1.312381
Thread-3: Price 2: 1.312381
Thread-4: Price1: 9.619444
Thread-4: Price 2: 5.728189
Thread-1: Price 2: 5.728189
Writer: Prices hava been modified.
Thread-0: Price1: 7.373355
Thread-2: Price1: 7.373355
Thread-0: Price 2: 5.728189
Thread-1: Price1: 9.619444
Thread-1: Price 2: 5.728189
Thread-4: Price1: 9.619444
Thread-3: Price1: 9.619444
Thread-4: Price 2: 5.728189
Thread-4: Price1: 9.619444
Thread-1: Price1: 9.619444
Thread-0: Price1: 9.619444
Thread-2: Price 2: 5.728189
Thread-0: Price 2: 5.728189
Thread-1: Price 2: 5.728189
Thread-4: Price 2: 5.728189
Thread-4: Price1: 9.619444
Thread-3: Price 2: 5.728189
Thread-4: Price 2: 5.728189
Thread-0: Price1: 9.619444
Thread-0: Price 2: 5.728189
Thread-0: Price1: 9.619444
Thread-2: Price1: 9.619444
Thread-2: Price 2: 5.728189
Thread-2: Price1: 9.619444
Thread-2: Price 2: 5.728189
Thread-2: Price1: 9.619444
Thread-2: Price 2: 5.728189
Thread-2: Price1: 9.619444
Thread-2: Price 2: 5.728189
Thread-2: Price1: 9.619444
Thread-2: Price 2: 5.728189
Thread-0: Price 2: 5.728189
Thread-0: Price1: 9.619444
Thread-0: Price 2: 5.728189
Thread-3: Price1: 9.619444
Thread-3: Price 2: 5.728189
Thread-3: Price1: 9.619444
Thread-3: Price 2: 5.728189
Thread-3: Price1: 9.619444
Thread-3: Price 2: 5.728189
Thread-3: Price1: 9.619444
Thread-3: Price 2: 5.728189
Thread-3: Price1: 9.619444
Thread-3: Price 2: 5.728189
Thread-3: Price1: 9.619444
Thread-3: Price 2: 5.728189
从结果中就可以看出 ReentrantWriteLock类有两种锁:一种是读操作锁 另一种是写操作锁 读操作锁通过ReadWriteLock接口的ReadLock方法获取的 这个锁实现了lock接口 所以我们可以使用lock unlock trylock方法 写操作锁是通过ReadWriteLock接口的WriteLock方法获取 当你获取lock接口的读锁时 不可以进行修改操作 不然会引起数据不一致的错误
3:修改锁的公平性
ReentrantLock和ReentranReadWriteLock类的构造器 都含有一个布尔参数 它允许你控制着两个类的行为 默认值是false 它称为非公平模式 在非公平模式下 当有很多线程在等待锁时 锁将选择他们中的一个来访问临界区 这个选择是没有任何约束的 如果默认值是true 则称为公平模式 在公平模式下 当有很多线程在等待锁时 锁将选择他们中的一个来访问临界区 而且选择的是等待时机最长的 这两种模式只适用于lock和unlock方法 而Lock接口的tryLock方法没有将现场置于休眠默认属性并不影响这个方法
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- Debian 7.x 安装Oracle JAVA
- springmvc实现url路由功能
- spring boot 配置 druid/** * 配置druid * Created by adam on 4/11/16. */ @Configuration public class D
- api接口rsa加密
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本