2015年3月10日

1. 概述

      java在多线程编程的过程中,为实现线程安全的编程提供了synchronized,关键字,该关键字的作用是为某一代码块加锁,从线程的角度来说,所有需要执行加了syhchronized的代码块的线程,都要排队依次来执行该代码块,从而来确保线程安全。

      为什么依次执行代码块就能确保线程安全呢?因为是在代码快里面有些操作的变量,是所有线程都想对其进行修改的,在这个过程中,要确保被修改的变量相对所有线程都是可见的,并且线程在执行代码块的时候,不被打断,也就是“原子性”,才能保证,该变量的值最终是有效的,并且所有线程对其的更改,都能正确的作用到该变量上面。扯的有点远了..

     使用synchronized加锁的方式可以有效的解决安全问题,然而,synchronized确带来了很大的性能问题,由于使所有线程都排队等待,如果想得到该锁,必须排队等待,如果有获得该锁的线程一直没有释放锁的话呢,后续的要使用该锁的线程会一直等待下去,这样的解决方式比较古板。

2,synchronized 与lock的使用区别

   整是由于synchronized有这样的缺点,所以,jdk1.5以后出现了lock,lock可以实现synchronized的所有功能,但是lock提供了多种灵活处理锁的机制,比如说,如果后续线程想得到该锁,lock制定了几种方案,1,尝试去得到该锁,如果得不到,那我在去做其他的事情,2,尝试得到该锁,如果得不到,我可以等待,但是我不能没有限制的“死等“,要等一段时间之后如果还得不到,我就做其他的事情。等等,lock在synchronized的基础上增加了这些处理方式,使得java在处理锁的过程更加灵活。

 synchronized是一个修饰符,而lock是一个接口,所以二者在使用的时候有所不同,lock 里面有一些方法,lock(),tryock(),tryLock(long time,TimeUnit unit),lockInterruptibly() 这些方法是获得锁的,unlock()是用来释放锁的。java里面lock的唯一的实现类是ReentrantLock

ReentrantLock的使用:

package com.pip.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TryLockSO {

	private int sharedVariable;
	private Lock lock=new ReentrantLock();
	
	public void addValue(){
		
		if(lock.tryLock()){
			try {
				sharedVariable++;
				System.out.println("Current Thread:"+Thread.currentThread().getName()+
						"SharedVariable"+sharedVariable);
				Thread.sleep(5000);
				lock.unlock();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else{
			try {
				Thread.sleep(5000);
				System.out.println("not get lock. Thread:"+Thread.currentThread().getName()+
						"SharedVariable----"+sharedVariable);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

}


3,读写锁(ReadWriteLock)

     继续讨论synchronized的缺陷,我们对于变量的操作有时候可以是读操作也可以是写操作,写操作跟写操作发生冲突,读操作跟写操作发生冲突,读跟读操作不发生冲突,synchronized的缺点就是将读操作跟读操作之间也实现互斥 。所以这样就做了一些不必要的互斥。

     针对这样的情况,就出现了ReadWriteLock,ReadwriteLock是一个接口,里面有readLock()writeLock()。分别获取读的锁和写的锁,通过这种方式,可以实现读操作的线程之间可以同时进行的,写操作顺序执行,写操作和读的操作都是顺序执行的。

下面试一个测试类,里面有读操作和写操作,并且分别用读的锁和写的锁来加锁。

package com.pip.lock3;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SharedObject {

	private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
   
	public void read(){
		lock.readLock().lock();
		for(int i=0;i<10;i++){
			System.out.println("CurrentThread :-----"+Thread.currentThread().getName()+" value: "+i);
		}
		lock.readLock().unlock();
	}

	public void write(){
		lock.writeLock().lock();
		for(int i=0;i<10;i++){
			System.out.println("CurrentThread :-----"+Thread.currentThread().getName()+" value: "+i);
		}	
		lock.writeLock().unlock();
	}
	
	
}

测试类:

package com.pip.lock3;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

public class TestLock {

	@Test
	public void testReadLock() {
		final SharedObject so = new SharedObject();
		Runnable task1 = new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				so.read();
			}
		};

		ExecutorService es = Executors.newCachedThreadPool();
		es.submit(task1);
		es.submit(task1);
		es.shutdown();

	}

	@Test
	public void testWriteLock(){
		final SharedObject so=new SharedObject();
		Runnable task1=new Runnable(){
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
			so.write();	
		   }			
		};
		
		ExecutorService es=Executors.newCachedThreadPool();
		es.submit(task1);
		es.submit(task1);
		es.shutdown();
		
	}
	
	@Test
	public void testReadWrite(){
		final SharedObject so=new SharedObject();
		Runnable readTask=new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				so.read();
			}			
		};
		
		Runnable writeTask=new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				so.write();
			}		
		};
		
		ExecutorService es=Executors.newCachedThreadPool();
		es.submit(readTask);
		es.submit(writeTask);
		es.shutdown();
	}
	
}


通过运行结果可以看出:读跟读的操作可以同时进行,写跟写的操作和写跟读的操作是互斥的。


4, 综上所述,sychronized和lock的区别,

(1) synchronized 是修饰符,lock是java里面的接口。

(2)lock可是实现synchoronized的所有功能,并且提供了更加灵活的的处理锁的方式。

(3)synchronized发生异常的时候,可以自动释放锁,而lock必须手动的释放锁,在finally里面。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值