线程Lock

我们之前学习了synchronized,今天来介绍一下lock。lock与synchronized一样都是为了多线程在竞争公共资源时,能不发生冲突,就是一个线程获取了锁,就去执行代码块,其它线程只能等待第一个线程执行完同步代码块,才能有机会获取到synchronized锁对象。

  lock与synchronized最大的区别是,lock锁的释放需要程序员手动调用unlock,一般放在要同步的代码的最后调用unlock,或者try..catch..finally中的finally里调用unlock。当然,从lock释放锁的灵活性上来说,lock的性能更高些,因为synchronized必须等待代码块整个执行完毕才能自动释放锁,而unlock可由程序员手动释放,随时释放,只要不影响多线程同步。

synchronized与lock的示例代码如下:

 

package cn.itcast.heima2;

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


public class LockTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new LockTest().init();
	}
	
	private void init(){
		final Outputer outputer = new Outputer();
		new Thread(new Runnable(){
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					outputer.output("gaoxiaowei");
				}
				
			}
		}).start();
		
		new Thread(new Runnable(){
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					outputer.output("liudehua");
				}
				
			}
		}).start();
		
	}

	static class Outputer{
		Lock lock = new ReentrantLock();
		public void output(String name){
			int len = name.length();
			lock.lock();
			try{
				for(int i=0;i<len;i++){
					System.out.print(name.charAt(i));
				}
				System.out.println();
			}finally{
				lock.unlock();
			}
		}
		
		public synchronized void output2(String name){
			int len = name.length();
			for(int i=0;i<len;i++){
					System.out.print(name.charAt(i));
			}
			System.out.println();
		}
		
		public static synchronized void output3(String name){
			int len = name.length();
			for(int i=0;i<len;i++){
					System.out.print(name.charAt(i));
			}
			System.out.println();
		}	
	}
}

其中output函数使用了lock,于是两个thread不断输出字符串“gaoxiaowei”,“liudehua”,就不会乱,不会出现类似于这样的输出:"gaoxliudehuaiaowei"

其中output2函数使用了synchronized ,它也可以达到多线程同步的效果。

           值得注意的是如果 生成两个Outputer对象就不行了,例如再创建一个Outputer对象,    final Outputer outputer2 = new Outputer();  然后让输出liudehua的线程(第2个new Thread) 使用outputer2.output照样会乱,例如类似于这样的输出:"gaoxliudehuaiaowei"。这是因为synchronized或lock,创建的锁对象就是output对象。多线程调用同一Outputer 对象的output函数可以达到同效果,但是当一个线程使用output对象,第二个线程使用output2对象,那么这两个线程在调用output.output()函数与output2.output()函数时,是不会同步的,因为它们分别持有的锁是output.this 与 output2.this,是两把不同的锁,各自玩各自的,互相不受影响,都无法锁住对方。

 

其中其中output3函数使用了synchronized, output3注意了,是一个静态函数,synchronized关键字对应的锁对象是 Output.class类的字节码,它能锁住所有类对象,这个时候即使创建了inal Outputer outputer2 = new Outputer(); 让线程1调用 outputer.output3(),线程2调用output2.output3(), 是不会出现错乱的,因为outputer与output2都属于Output类型,synchronized关键字对应的锁对象是 Output.class类的字节码,它们在执行output3()函数时,用的是同一把锁:Output.class。因此最终还是可以达到多个线程同步输出字符串到屏幕设备的。

 

但是,无论是synchronized,还是我们上述讲的lock, 性能都很差,因为它们的锁有些盲目,比如当2个线程都是读数据,并没有去写数据,所以不会出现多线程读取多乱问题。这个时候synchronized和lock就有点死板了,当第1个线程读取变量值(或数据)的时候,线程2也想读,但是必须得等线程1把锁释放了才行,即使线程2不是来捣乱的。

要改善读-读性能问题,需要使用ReentrantReadWriteLock(读写锁)来分别创建读锁 和 写锁。读锁就能解决上述问题,让读--读自由。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冉航--小虾米

希望得到您的鼓励和交流

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值