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里面。
1万+

被折叠的 条评论
为什么被折叠?



