线程Lock

举报
yd_57386892 发表于 2021/04/25 00:01:03 2021/04/25
4.6k+ 0 0
【摘要】 我们之前学习了synchronized,今天来介绍一下lock。lock与synchronized一样都是为了多线程在竞争公共资源时,能不发生冲突,就是一个线程获取了锁,就去执行代码块,其它线程只能等待第一个线程执行完同步代码块,才能有机会获取到synchronized锁对象。   lock与synchronized最大的区别是,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(读写锁)来分别创建读锁 和 写锁。读锁就能解决上述问题,让读--读自由。

文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/116096384

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。