Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我们拿Java线程(二)中的一个例子简单的实现一下和sychronized一样的效果,代码如下:

  1. public class LockTest {
  2. public static void main(String[] args) {
  3. final Outputter1 output = new Outputter1();
  4. new Thread() {
  5. public void run() {
  6. output.output("zhangsan");
  7. };
  8. }.start();
  9. new Thread() {
  10. public void run() {
  11. output.output("lisi");
  12. };
  13. }.start();
  14. }
  15. }
  16. class Outputter1 {
  17. private Lock lock = new ReentrantLock();// 锁对象
  18. public void output(String name) {
  19. // TODO 线程输出方法
  20. lock.lock();// 得到锁
  21. try {
  22. for(int i = 0; i < name.length(); i++) {
  23. System.out.print(name.charAt(i));
  24. }
  25. } finally {
  26. lock.unlock();// 释放锁
  27. }
  28. }
  29. }

这样就实现了和sychronized一样的同步效果,需要注意的是,用sychronized修饰的方法或者语句块在代码执行完之后锁自动释放,而用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内。

如果说这就是Lock,那么它不能成为同步问题更完美的处理方式,下面要介绍的是读写锁(ReadWriteLock),我们会有一种需求,在对数据进行读写的时候,为了保证数据的一致性和完整性,需要读和写是互斥的,写和写是互斥的,但是读和读是不需要互斥的,这样读和读不互斥性能更高些,来看一下不考虑互斥情况的代码原型:

  1. public class ReadWriteLockTest {
  2. public static void main(String[] args) {
  3. final Data data = new Data();
  4. for (int i = 0; i < 3; i++) {
  5. new Thread(new Runnable() {
  6. public void run() {
  7. for (int j = 0; j < 5; j++) {
  8. data.set(new Random().nextInt(30));
  9. }
  10. }
  11. }).start();
  12. }
  13. for (int i = 0; i < 3; i++) {
  14. new Thread(new Runnable() {
  15. public void run() {
  16. for (int j = 0; j < 5; j++) {
  17. data.get();
  18. }
  19. }
  20. }).start();
  21. }
  22. }
  23. }
  24. class Data {
  25. private int data;// 共享数据
  26. public void set(int data) {
  27. System.out.println(Thread.currentThread().getName() + "准备写入数据");
  28. try {
  29. Thread.sleep(20);
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. this.data = data;
  34. System.out.println(Thread.currentThread().getName() + "写入" + this.data);
  35. }
  36. public void get() {
  37. System.out.println(Thread.currentThread().getName() + "准备读取数据");
  38. try {
  39. Thread.sleep(20);
  40. } catch (InterruptedException e) {
  41. e.printStackTrace();
  42. }
  43. System.out.println(Thread.currentThread().getName() + "读取" + this.data);
  44. }
  45. }

部分输出结果:

  1. Thread-1准备写入数据
  2. Thread-3准备读取数据
  3. Thread-2准备写入数据
  4. Thread-0准备写入数据
  5. Thread-4准备读取数据
  6. Thread-5准备读取数据
  7. Thread-2写入12
  8. Thread-4读取12
  9. Thread-5读取5
  10. Thread-1写入12

我们要实现写入和写入互斥,读取和写入互斥,读取和读取互斥,在set和get方法加入sychronized修饰符:

  1. public synchronized void set(int data) {...}
  2. public synchronized void get() {...}

部分输出结果:

  1. Thread-0准备写入数据
  2. Thread-0写入9
  3. Thread-5准备读取数据
  4. Thread-5读取9
  5. Thread-5准备读取数据
  6. Thread-5读取9
  7. Thread-5准备读取数据
  8. Thread-5读取9
  9. Thread-5准备读取数据
  10. Thread-5读取9

我们发现,虽然写入和写入互斥了,读取和写入也互斥了,但是读取和读取之间也互斥了,不能并发执行,效率较低,用读写锁实现代码如下:

  1. class Data {
  2. private int data;// 共享数据
  3. private ReadWriteLock rwl = new ReentrantReadWriteLock();
  4. public void set(int data) {
  5. rwl.writeLock().lock();// 取到写锁
  6. try {
  7. System.out.println(Thread.currentThread().getName() + "准备写入数据");
  8. try {
  9. Thread.sleep(20);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. this.data = data;
  14. System.out.println(Thread.currentThread().getName() + "写入" + this.data);
  15. } finally {
  16. rwl.writeLock().unlock();// 释放写锁
  17. }
  18. }
  19. public void get() {
  20. rwl.readLock().lock();// 取到读锁
  21. try {
  22. System.out.println(Thread.currentThread().getName() + "准备读取数据");
  23. try {
  24. Thread.sleep(20);
  25. } catch (InterruptedException e) {
  26. e.printStackTrace();
  27. }
  28. System.out.println(Thread.currentThread().getName() + "读取" + this.data);
  29. } finally {
  30. rwl.readLock().unlock();// 释放读锁
  31. }
  32. }
  33. }

部分输出结果:

  1. Thread-4准备读取数据
  2. Thread-3准备读取数据
  3. Thread-5准备读取数据
  4. Thread-5读取18
  5. Thread-4读取18
  6. Thread-3读取18
  7. Thread-2准备写入数据
  8. Thread-2写入6
  9. Thread-2准备写入数据
  10. Thread-2写入10
  11. Thread-1准备写入数据
  12. Thread-1写入22
  13. Thread-5准备读取数据

从结果可以看出实现了我们的需求,这只是锁的基本用法,锁的机制还需要继续深入学习。

本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7461369,转载请注明。

在java中有两种方式实现原子性操作(即同步操作):
1)使用同步关键字synchronized
2)使用lock锁机制其中也包括相应的读写锁

package com.xiaohao.test;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Test {
public static void main(String[] args) {
final LockTest lock=new LockTest();
//输出张三
new Thread(){
public void run(){
lock.test("张三张三张三张三张三张三张三张三张三张三");
}
}.start();

//输出李四
new Thread(){
public void run(){
lock.test("李四李四李四李四李四李四李四李四李四李四");System.out.println

("\n---------------------------------------------------------------");
}
}.start();

//---------------------------------------------------------------
//模拟写入数据的
for (int i = 0; i < 3; i++) {
new Thread(){
public void run() {
for (int j = 0; j < 5; j++) {
// lock.set(new Random().nextInt(30));
lock.set2(new Random().nextInt(30));

}
}
}.start();

}
//模拟读取数据的
for (int i = 0; i < 3; i++) {
new Thread(){
public void run() {
for (int j = 0; j < 5; j++) {
// lock.get();
lock.get2();
}
}
}.start();
}

}
}

class LockTest{
private Lock lock=new ReentrantLock(); //创建普通的锁
private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();//创建读写锁
private int data;// 共享数据

//实现同步的方法一 使用同步关键字 synchronized
public synchronized void test(String name){
//下面的相关操作是一个原子性的操作
// lock.lock();// 得到锁
try {
for(int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
} finally {
// lock.unlock();// 释放锁
}
}

//实现同步的方法二 使用lock锁机制
public void test2(String name){
//下面的相关操作是一个原子性的操作
lock.lock();// 得到锁
try {
for(int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
} finally {
lock.unlock();// 释放锁
}
}

//使用set方法模拟写入数据
//使用 synchronized 实现了读读,写写,读写之间的互斥 ,但读读之间的互斥是没有什么必要的
public synchronized void set(int data){
System.out.println(Thread.currentThread().getName() + "准备写入数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data;
System.out.println(Thread.currentThread().getName() + "写入" + this.data);
}

//使用get方法模拟读取数据
//使用 synchronized 实现了读读,写写,读写之间的互斥 ,但读读之间的互斥是没有什么必要的
public synchronized void get() {
System.out.println(Thread.currentThread().getName() + "准备读取数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "读取" + this.data);
}

//使用set方法模拟写入数据
//使用 读写锁实现了写写,读写之间的互斥 ,但读读之间的互斥是没有什么必要的
public void set2(int data){
readWriteLock.writeLock().lock();//获取写入锁
try{
System.out.println(Thread.currentThread().getName() + "准备写入数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data;
System.out.println(Thread.currentThread().getName() + "写入" + this.data);
}
finally{
readWriteLock.writeLock().unlock();
}
}

//使用get方法模拟读取数据
//使用 读写锁实现了写写,读写之间的互斥 ,但读读之间的互斥是没有什么必要的
public void get2() {
//获取相应的读锁
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "准备读取数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "读取" + this.data);
}
finally{
// 释放相应的写锁
readWriteLock.readLock().unlock();
}
}

}

线程同步经典版:

package com.xiaohao.test;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Test2{

public static void main(String[] args){

final LockTest2 lockTest=new LockTest2();

for(int i=0;i<3;i++)   {

new Thread(){

public void run(){

try {

for (int j = 0; j < 3; j++) {

lockTest.setValue();

}    } catch (InterruptedException e) {

// TODO Auto-generated catch block     e.printStackTrace();

}

}

}.start();

}

for(int i=0;i<3;i++)   {

new Thread(){

public void run(){

try {

for (int j = 0; j < 3; j++) {

lockTest.getValue();

}

} catch (InterruptedException e)

{     // TODO Auto-generated catch block     e.printStackTrace();    }

}

}.start();

}

}

}

class  LockTest2 {

int data=0;

ReentrantReadWriteLock lock= new ReentrantReadWriteLock();// 锁对象

public void setValue() throws InterruptedException{

lock.writeLock().lock();

System.out.println("正在使用写锁......");

data=(int) (Math.random()*10);

System.out.println("正在写入:"+data);

Thread.sleep(500);

System.out.println("写锁调用完毕---------------------------");

lock.writeLock().unlock();  }

public void getValue() throws InterruptedException{

lock.readLock().lock();

System.out.println("正在使用读锁...........................................");

System.out.println("正在读入:"+data);    Thread.sleep(500);

System.out.println("读锁调用完毕......");

lock.readLock().unlock();

}

}

**** 当一个线程进入了一个对象是的synchronized方法,那么其它线程还能掉否调用此对象的其它方法?

这个问题需要分几种情况进行讨论。

1)查看其它方法是否使用了同步关键字(synchronized)修饰,如果没有的话就可以调用相关的方法。

2)在当前synchronized方法中是否调用了wait方法,如果调用了,则对应的锁已经释放,可以访问了。

3)如果其它方法也使用synchronized修饰,并且当前同步方法中没有调用wait方法的话,这样是不允许访问的。

4)如果其它方法是静态方法的话,由于静态方法和对象是扯不上什么关系,对于静态同步方法而言,其对应的同步监视器为当前类的字节码

所以肯定可以访问的了。

最新文章

  1. Java 实现MapReduce函数
  2. HDU 3006
  3. 关于 Redis 访问安全性的问题
  4. 细雨学习笔记:Jmeter上一个请求的结果作为下一个请求的参数--使用正则提取器
  5. MongoDB之【增加用户认证、增加用户、删除用户、修改用户密码、读写权限、只读权限】
  6. Java基础知识强化32:String类之String类的判断功能
  7. JS时间戳与日期类型格式相互转换
  8. CSS IE的bug
  9. CI 结合 vue.js 的搜索功能模块
  10. Spring框架学习笔记(4)——配置bean more
  11. MFC多语言程序版本,在不同的windows系统上的使用
  12. 源生API解析XML文档与dom4j解析XML文档
  13. go语言数据库操作,xorm框架
  14. 一个axios的简单教程
  15. VM虚拟机配置固定IP
  16. thinkphp5 速查表
  17. openstack 问题一览(持续总结中)
  18. linux yum 安装wget、gcc、ifconfig、vim、setup
  19. Fiddler4无法抓取HttpWebRequest本地请求的解决办法
  20. #Go# 点滴积累

热门文章

  1. 跨站脚本攻击XSS
  2. IT传统组织结构及新型扁平化组织
  3. ssc
  4. 说说设计模式~桥梁模式(Bridge)
  5. [javaweb]Java过滤器与包装设计模式的实用案例.
  6. java初学者应掌握的30个基本概念
  7. linux执行sh脚本文件命令
  8. AngularJs ui-router 路由的简单介绍
  9. HTML5第一讲
  10. JAVA编程“性能说”(java编程需要做的26件事)