java并发系列之synchronized与lock

synchronized
package thread;

/**
 * synchronized修饰实例方法、静态方法、代码块,修饰实例方法和代码块时候用this对象当锁,修改静态方法时用类的class对象当锁	
 * synchronized是悲观锁,synchronized和ReentrantLock等独占锁就是悲观锁思想的实现
 * synchronized是可重入锁
 * synchronized是非公平锁
 * 做为锁的条件:必须是对象且被多个线程共享才能做为锁
 *
 */
public class SynchronizedDemo {
	private int a;
	
	public int getA() {
		return a;
	}

	public void setA(int a) {
			
		this.a = a;
	}

	public void add(){
		synchronized(this){
			int x = getA();
			setA(x+1);
		}
	}
	
	
	public static void main(String[] args) throws InterruptedException {
		final SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
		
		for (int i = 0; i < 100000; i++) {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					
					synchronizedDemo.add();
				}
			}).start();
			
		}
		
		
		Thread.sleep(10000);
		System.err.println(synchronizedDemo.getA());
	}
}

 

lock
package thread;

import java.util.concurrent.locks.ReentrantLock;


/**
 * 一、锁像synchronized同步块同样,是一种线程同步机制,但比Java中的synchronized同步块更复杂,由于锁(以及其它更高级的线程同步机制)
 * 是由synchronized同步块的方式实现的
 * 
 * 二、乐观锁与悲观锁
 *    乐观锁适用于读比较多的场景,悲观锁适用于写比较多的场景,不加锁会带来大量的性能提高
 *    乐观锁常见的两种实现方式:版本号机制或CAS算法实现
 * 	      版本号机制:通常是在数据表中加上一个数据版本号version字段,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,
 *    在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,不然重试更新操做,直到更新成功	
 *
 * 三、CAS算法
 *    即 compare and swap(比较与交换),是一种有名的无锁算法,即不使用锁的状况下实现多线程之间的变量同步,也就是在没有线程被阻塞的状况下实现变量的同步,
 *    因此也叫非阻塞同步
 *  check and act模式,先检查后操做模式	首先检查一个变量的值,而后再基于这个值作一些操做,check then act操做必须是原子的。
 *  原子就是说”check“操做和”act“被当作一个原子代码块执行。不存在多个线程同时执行原子块
 *  CAS有3个操做数,内存值V,预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改成B,不然什么都不作
 *  
 * 四、可重入锁:假如一把锁锁了n个地方,那么只要获得这把锁,那n个地方均可以访问
 * 
 * 五、独享锁和共享锁
 * 	独享锁:是指该锁一次只能被一个线程所持有。实现:ReentrantLock
 *	共享锁:是指该锁可被多个线程所持有。实现:ReadWriteLock,读锁是共享锁,写锁是独享锁。由于读读能够同时进行,而读写、写写不能同时进行
 *
 * 六、公平锁、非公平锁:公平锁是指多个线程按照申请锁的顺序来获取锁。
 * 
 * 七、分段锁 
 * 分段锁实际上是一种锁的设计,并非具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是经过分段锁的形式来实现高效的并发操做
 * 当须要put元素的时候,并非对整个hashmap进行加锁,而是先经过hashcode来知道他要放在哪个分段中,而后对这个分段进行加锁,因此当多线程put的时候,
 * 只要不是放在一个分段中,就实现了真正的并行的插入
 * 
 * 八、偏向锁/轻量级锁/重量级锁,这三种锁是指锁的状态,而且是针对Synchronized
 * 
 * 九、AQS是抽象队列同步器,维护了一个volatile int state(表明共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)
 * 
 * 十、自旋锁:在Java中,自旋锁是指尝试获取锁的线程不会当即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减小线程上下文切换的消耗,缺点是循环会消耗CPU
 * 获取不到锁的线程要么阻塞,要么自旋
 */
public class LockDemo {
	
	private int a;
	//经过构造函数指定是否为公平锁
	private ReentrantLock reentrantLock=new ReentrantLock(true);
	//private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock();
	
	public int getA() {
		return a;
	}

	public void setA(int a) {
			
		this.a = a;
	}

	public void add(){
		
		reentrantLock.lock();
		//reentrantReadWriteLock.readLock().lock();
		
		try {
			int x = getA();
			setA(x+1);
		} finally {
			reentrantLock.unlock();
			//reentrantReadWriteLock.readLock().unlock();
		}
		
	}
	
	
	public static void main(String[] args) throws InterruptedException {
		final LockDemo lockDemo = new LockDemo();
		
		
		for (int i = 0; i < 100000; i++) {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					
					lockDemo.add();
				}
			}).start();
			
		}
		
		
		Thread.sleep(10000);
		System.err.println(lockDemo.getA());
	}
}

 

二者区别
1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;

2.synchronized没法判断是否获取到锁,Lock能够判断是否获取到锁;

3.synchronized会自动释放锁(执行完代码或发生异常会释放锁),Lock需在finally中手工释放锁,不然容易形成线程死锁;

4.用synchronized关键字的两个线程1和线程2,若是当前线程1得到锁,线程2线程等待。若是线程1阻塞,线程2则会一直等待下去,而Lock锁就不必定会等待下去,若是尝试获取不到锁,线程能够不用一直等待就结束了;

5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可中断、能够设置是否公平

6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少许的同步问题
相关文章
相关标签/搜索