Synchronized与Lock
Synchronized与Lock
EveryDayNew 发表于1年前
Synchronized与Lock
  • 发表于 1年前
  • 阅读 57
  • 收藏 4
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

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

说起来蛮简单,而实际中编程 ,最难得地方有两点

1、确定并发间隙

2、确定锁的对象

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

eg1、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();;
	}
}

 

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

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();;
	}
}

eg3、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();;
	}
}

 

LOCK

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

共有 人打赏支持
粉丝 5
博文 25
码字总数 31262
×
EveryDayNew
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: