**** 当一个线程进入了一个对象是的 synchronized 方法, 那么其它线程还能掉否调用此对象的其它方法?
这个问题需要分几种情况进行讨论.
1)查看其它方法是否使用了同步关键字 (synchronized) 修饰, 如果没有的话就可以调用相关的方法.
2)在当前 synchronized 方法中是否调用了 wait 方法, 如果调用了, 则对应的锁已经释放, 可以访问了.
3)如果其它方法也使用 synchronized 修饰, 并且当前同步方法中没有调用 wait 方法的话, 这样是不允许访问的.
4)如果其它方法是静态方法的话, 由于静态方法和对象是扯不上什么关系, 对于静态同步方法而言, 其对应的同步监视器为当前类的字节码
所以肯定可以访问的了.
Lock 是 java.util.concurrent.locks http://blog.csdn.net/ghsau/article/details/7461369/ 包下的接口, Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作, 它能以更优雅的方式处理线程同步问题, 我们拿 Java 线程(二) http://blog.csdn.net/ghsau/article/details/7424694 中的一个例子简单的实现一下和 sychronized 一样的效果, 代码如下:
[java] view plain http://blog.csdn.net/ghsau/article/details/7461369/ copy http://blog.csdn.net/ghsau/article/details/7461369/
- public class LockTest {
- public static void main(String[] args) {
- final Outputter1 output = new Outputter1();
- new Thread() {
- public void run() {
- output.output("zhangsan");
- };
- }.start();
- new Thread() {
- public void run() {
- output.output("lisi");
- };
- }.start();
- }
- }
- class Outputter1 {
- private Lock lock = new ReentrantLock();// 锁对象
- public void output(String name) {
- // TODO 线程输出方法
- lock.lock();// 得到锁
- try {
- for(int i = 0; i < name.length(); i++) {
- System.out.print(name.charAt(i));
- }
- } finally {
- lock.unlock();// 释放锁
- }
- }
- }
这样就实现了和 sychronized 一样的同步效果, 需要注意的是, 用 sychronized 修饰的方法或者语句块在代码执行完之后锁自动释放, 而用 Lock 需要我们手动释放锁, 所以为了保证锁最终被释放(发生异常情况), 要把互斥区放在 try 内, 释放锁放在 finally 内.
如果说这就是 Lock, 那么它不能成为同步问题更完美的处理方式, 下面要介绍的是读写锁(ReadWriteLock), 我们会有一种需求, 在对数据进行读写的时候, 为了保证数据的一致性和完整性, 需要读和写是互斥的, 写和写是互斥的, 但是读和读是不需要互斥的, 这样读和读不互斥性能更高些, 来看一下不考虑互斥情况的代码原型:
[java] view plain http://blog.csdn.net/ghsau/article/details/7461369/ copy http://blog.csdn.net/ghsau/article/details/7461369/
- public class ReadWriteLockTest {
- public static void main(String[] args) {
- final Data data = new Data();
- for (int i = 0; i < 3; i++) {
- new Thread(new Runnable() {
- public void run() {
- for (int j = 0; j < 5; j++) {
- data.set(new Random().nextInt(30));
- }
- }
- }).start();
- }
- for (int i = 0; i < 3; i++) {
- new Thread(new Runnable() {
- public void run() {
- for (int j = 0; j < 5; j++) {
- data.get();
- }
- }
- }).start();
- }
- }
- }
- class Data {
- private int data;// 共享数据
- public 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);
- }
- public 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);
- }
- }
部分输出结果:
[java] view plain http://blog.csdn.net/ghsau/article/details/7461369/ copy http://blog.csdn.net/ghsau/article/details/7461369/
Thread-1 准备写入数据
Thread-3 准备读取数据
Thread-2 准备写入数据
Thread-0 准备写入数据
Thread-4 准备读取数据
Thread-5 准备读取数据
Thread-2 写入 12
Thread-4 读取 12
Thread-5 读取 5
Thread-1 写入 12
我们要实现写入和写入互斥, 读取和写入互斥, 读取和读取互斥, 在 set 和 get 方法加入 sychronized 修饰符:
[java] view plain http://blog.csdn.net/ghsau/article/details/7461369/ copy http://blog.csdn.net/ghsau/article/details/7461369/
- public synchronized void set(int data) {...}
- public synchronized void get() {...}
部分输出结果:
[java] view plain http://blog.csdn.net/ghsau/article/details/7461369/ copy http://blog.csdn.net/ghsau/article/details/7461369/
Thread-0 准备写入数据
Thread-0 写入 9
Thread-5 准备读取数据
Thread-5 读取 9
Thread-5 准备读取数据
Thread-5 读取 9
Thread-5 准备读取数据
Thread-5 读取 9
Thread-5 准备读取数据
Thread-5 读取 9
我们发现, 虽然写入和写入互斥了, 读取和写入也互斥了, 但是读取和读取之间也互斥了, 不能并发执行, 效率较低, 用读写锁实现代码如下:
[java] view plain http://blog.csdn.net/ghsau/article/details/7461369/ copy http://blog.csdn.net/ghsau/article/details/7461369/
- class Data {
- private int data;// 共享数据
- private ReadWriteLock rwl = new ReentrantReadWriteLock();
- public void set(int data) {
- rwl.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 {
- rwl.writeLock().unlock();// 释放写锁
- }
- }
- public void get() {
- rwl.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 {
- rwl.readLock().unlock();// 释放读锁
- }
- }
- }
部分输出结果:
[java] view plain http://blog.csdn.net/ghsau/article/details/7461369/ copy http://blog.csdn.net/ghsau/article/details/7461369/
Thread-4 准备读取数据
Thread-3 准备读取数据
Thread-5 准备读取数据
Thread-5 读取 18
Thread-4 读取 18
Thread-3 读取 18
Thread-2 准备写入数据
Thread-2 写入 6
Thread-2 准备写入数据
Thread-2 写入 10
Thread-1 准备写入数据
Thread-1 写入 22
Thread-5 准备读取数据
从结果可以看出实现了我们的需求, 这只是锁的基本用法, 锁的机制还需要继续深入学习.
- 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();
- }
- }
来源: http://www.bubuko.com/infodetail-2666686.html