Synchronized与Lock

Synchronized是并发中使用最频繁的关键字了,它可使用在方法、代码块上,表示对该段代码加锁,而必需要持有锁才能执行这段代码。Synchronized具备互斥性。java

提及来蛮简单,而实际中编程 ,最可贵地方有两点编程

一、肯定并发间隙多线程

二、肯定锁的对象并发

作好这两点才能处理好锁的粒度,是并发的性能更好。ide

eg一、Synchronized加在静态方法上,不一样的线程调用这两个方法互斥。此时synchronize锁的是该类性能

public class SynchronizeDemo1 {
	public synchronized static void fool1() throws Exception{
		System.out.println("fool1...开始");
		Thread.sleep(10000L);
		System.out.println("fool1...结束");
	}
	public synchronized static void fool2() throws Exception{
		System.out.println("fool2...开始");
		Thread.sleep(5000L);
		System.out.println("fool2...结束");
	}
	
	public static void main(String args[]){
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					SynchronizeDemo1.fool1();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					SynchronizeDemo1.fool2();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();;
	}
}

 

eg二、Synchronized加在成员方法上,不一样的线程调用同一对象的成员方法互斥this

package com.base.thread.synchronize;

public class SynchronizeDemo2 {
	public synchronized void fool1() throws Exception{
		System.out.println("fool1...开始");
		Thread.sleep(10000L);
		System.out.println("fool1...结束");
	}
	public synchronized void fool2() throws Exception{
		System.out.println("fool2...开始");
		Thread.sleep(5000L);
		System.out.println("fool2...结束");
	}
	
	public static void main(String args[]){
		final SynchronizeDemo2 synchronizeDemo2 = new SynchronizeDemo2();
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
//					new SynchronizeDemo2().fool1();
					synchronizeDemo2.fool1();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
//					new SynchronizeDemo2().fool2();
					synchronizeDemo2.fool1();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();;
	}
}

eg三、foo3和foo4不互斥,foo1和foo4互斥,foo2和foo3互斥线程

 

public class SynchronizeDemo3 {
	public static synchronized void fool1() throws Exception{
		System.out.println("fool1...开始");
		Thread.sleep(10000L);
		System.out.println("fool1...结束");
	}
	public synchronized void fool2() throws Exception{
		System.out.println("fool2...开始");
		Thread.sleep(5000L);
		System.out.println("fool2...结束");
	}
	
	public void fool3() throws Exception{
		synchronized(this){
			System.out.println("fool3...开始");
			Thread.sleep(5000L);
			System.out.println("fool3...结束");
		}
	}
	public void fool4() throws Exception{
		synchronized(SynchronizeDemo3.class){
			System.out.println("fool4...开始");
			Thread.sleep(5000L);
			System.out.println("fool4...结束");
		}
	}
	public static void main(String args[]){
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					new SynchronizeDemo3().fool3();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					new SynchronizeDemo3().fool4();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();;
	}
}

 

LOCKcode

Lock比synchronized更加面向对象,锁自己就是一个对象。两个线程执行的代码片断要实现同步互斥的效果,它们必须用同一个Lock对象。对象

ReentrantLock

ReentrantLock是Lock的实现,被称做重入锁,它的功能比Synchronized强大,可是jdk1.6以后二者性能差异不大,Synchronized使用更简单清晰,因此多线程加锁仍是首选Synchronized。

ReentrantLock提供了公平和非公平两种锁。经过构造方法能够实现,可是公平锁的性能远远低于非公平锁,所以非特殊状况优先非公平锁。

注意:ReenTrantLock使用以后,必须释放锁。

ReentrantLock 锁提供了以下重要的方法:

lock():得到锁,若是锁已经被占用,则等待

lockInterruptibly():得到锁,但优先响应中断

tryLock():尝试得到锁,若是成功,返回true,失败返回false。该方法不等待,当即返回

unlock():释放锁

ReentrantReadWriteLock 读写锁

分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。若是代码是只读数据,能够不少人同时读,但不能同时写,那就上读锁;若是你的代码修改数据,只能有一我的在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!

 

public class ReadWriteLockTest{
	private Integer num = 0;
	private Lock lock = new ReentrantLock();
	private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
	private ReadLock readLock = reentrantReadWriteLock.readLock();
	private WriteLock writeLock = reentrantReadWriteLock.writeLock();

	public int read1(){
		try{
			lock.lock();
			Thread.sleep(10L);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
		return num;
	}
	public void write1(){
		try{
			lock.lock();
			num++;
		}finally{
			lock.unlock();
		}
	}
	
	public int read2(){
		try{
			readLock.lock();
			Thread.sleep(10L);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			readLock.unlock();
		}
		return num;
	}
	public void write2(){
		try{
			writeLock.lock();
			num++;
		}finally{
			writeLock.unlock();
		}
	}
	public Integer getNum() {
		return num;
	}
	public static void main(String args[]) throws Exception{
		long time1 = System.currentTimeMillis();
		final ReadWriteLockTest rwt = new ReadWriteLockTest();
		List<Thread> threadList = new ArrayList<>();
		for(int i = 0; i < 3000; i++){
			Thread t1 = new Thread(new Runnable() {
				@Override
				public void run() {
					rwt.write1();
//					rwt.write2();
				}
			});
			t1.start();
			Thread t2 = new Thread(new Runnable() {
				@Override
				public void run() {
					rwt.read1();
//					rwt.read2();
				}
			});
			t2.start();
			threadList.add(t1);
			threadList.add(t2);
		}
		
		for(Thread thread : threadList){
			thread.join();
		}
		System.out.println("num: " + rwt.getNum());
		System.out.println("耗时:" + (System.currentTimeMillis() - time1));
	} 
}

 

Condition

Condition能够替代传统的线程间通讯,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll()。

——为何方法名不直接叫wait()/notify()/nofityAll()?由于Object的这几个方法是final的,不可重写!

传统线程的通讯方式,Condition均可以实现。

注意,Condition是被绑定到Lock上的,要建立一个Lock的Condition必须用newCondition()方法。

 

Condition的强大之处在于它能够为多个线程间创建不一样的Condition

相关文章
相关标签/搜索