zoukankan      html  css  js  c++  java
  • ZZTHX-线程锁

    以前一直在做卡乐付,悲剧的是项目中的余额查询,超级转账和刷卡器相关的东西已经开发好了,我对这块还是比较好奇和感兴趣的,在项目空闲的时候我就开始尝试熟悉和了解这块的业务和代码。实践出真理,只有在实践中才能发现问题。真想自己去独立的去实现这块逻辑啊,加深一下理解。哈哈,卡乐付五期开发结束后,让我去完成ZZTHX的开发,机会终于来了,虽然时间比较紧张充满挑战,但是我还是很高兴的。在开发中遇到了各种各样的问题,我认为有必要去总结一下,记录一下自己的成长。ZZTHX了两种刷卡器磁条和IC刷卡器

         在开发中一般把比较耗时的操作,都会进行异步处理,这样不会阻塞主线程。项目中刷卡,刷卡器的加密都是异步处理的,譬如获取加密后的密码,首先要等待界面密码输入完成,之后去调用刷卡器加密,加密完成后才能返回密码。

     这里就要把异步操作转化成同步的,这里就用到了线程锁。

    1. 对象锁

          所有对象都自动含有单一的锁。      JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。      只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。      每当任务离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源。

    2. 类锁

          对于同步静态方法/静态变量互斥体,由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只由一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。一旦一个静态变量被作为synchronized block的互斥体。进入此同步区域时,都要先获得此静态变量的对象锁。

          由上述同步静态方法引申出一个概念,那就是类锁。其实系统中并不存在什么类锁。当一个同步静态方法被调用时,系统获取的其实就是代表该类的类对象的对象锁

    若要同时获取两种锁,同时获取类锁和对象锁是允许的,并不会产生任何问题,但使用类锁时一定要注意,一旦产生类锁的嵌套获取的话,就会产生死锁,因为每个class在内存中都只能生成一个Class实例对象。

    3. synchronized同步块

    3.1. 同步到单一对象锁

            当使用同步块时,如果方法下的同步块都同步到一个对象上的锁,则所有的任务(线程)只能互斥的进入这些同步块。         Resource1.java演示了三个线程(包括main线程)试图进入某个类的三个不同的方法的同步块中,虽然这些同步块处在不同的方法中,但由于是同步到同一个对象(当前对象 synchronized (this)),所以对它们的方法依然是互斥的。

     

    package com.zj.lock;
    import java.util.concurrent.TimeUnit;
     
    public class Resource1 {
        public void f() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in f()");
           synchronized (this) {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in f()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           }
        }
     
        public void g() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in g()");
           synchronized (this) {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in g()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           }
        }
     
        public void h() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in h()");
           synchronized (this) {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in h()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           }
        }
     
        public static void main(String[] args) {
           final Resource1 rs = new Resource1();
     
           new Thread() {
               public void run() {
                  rs.f();
               }
           }.start();
     
           new Thread() {
               public void run() {
                  rs.g();
               }
           }.start();
     
           rs.h();
        }
    }
    

    3.2. 同步到多个对象锁

            Resource1.java演示了三个线程(包括main线程)试图进入某个类的三个不同的方法的同步块中,这些同步块处在不同的方法中,并且是同步到三个不同的对象(synchronized (this),synchronized(syncObject1),synchronized (syncObject2)),所以对它们的方法中的临界资源访问是独立的。

    4. Lock对象锁

          除了使用synchronized外,还可以使用Lock对象来创建临界区。Resource3.java的演示效果同Resource1.java;Resource4.java的演示效果同

    package com.zj.lock;
    import java.util.concurrent.TimeUnit;
     
    public class Resource1 {
        public void f() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in f()");
           synchronized (this) {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in f()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           }
        }
     
        public void g() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in g()");
           synchronized (this) {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in g()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           }
        }
     
        public void h() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in h()");
           synchronized (this) {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in h()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           }
        }
     
        public static void main(String[] args) {
           final Resource1 rs = new Resource1();
     
           new Thread() {
               public void run() {
                  rs.f();
               }
           }.start();
     
           new Thread() {
               public void run() {
                  rs.g();
               }
           }.start();
     
           rs.h();
        }
    }
    

     

    package com.zj.lock;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
     
    public class Resource4 {
        private Lock lock1 = new ReentrantLock();
        private Lock lock2 = new ReentrantLock();
        private Lock lock3 = new ReentrantLock();
     
        public void f() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in f()");
           lock1.lock();
           try {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in f()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           } finally {
               lock1.unlock();
           }
        }
     
        public void g() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in g()");
           lock2.lock();
           try {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in g()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           } finally {
               lock2.unlock();
           }
        }
     
        public void h() {
           // other operations should not be locked...
           System.out.println(Thread.currentThread().getName()
                  + ":not synchronized in h()");
           lock3.lock();
           try {
               for (int i = 0; i < 5; i++) {
                  System.out.println(Thread.currentThread().getName()
                         + ":synchronized in h()");
                  try {
                      TimeUnit.SECONDS.sleep(3);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
               }
           } finally {
               lock3.unlock();
           }
        }
     
        public static void main(String[] args) {
           final Resource4 rs = new Resource4();
     
           new Thread() {
               public void run() {
                  rs.f();
               }
           }.start();
     
           new Thread() {
               public void run() {
                  rs.g();
               }
           }.start();
     
           rs.h();
        }
    }
    

      

     

    5. synchronized和lock的区别:

          Lock 的锁定是通过代码实现的,而 synchronized 是在 JVM 层面上实现的。

          synchronized 在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线程死锁。但是 Lock 的话就享受不到 JVM 带来自动的功能,出现异常时必须在 finally 将锁释放掉,否则将会引起死锁。

          在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

          ReentrantLock:

          ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

          Atomic:

          和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。

  • 相关阅读:
    HDU 5744
    HDU 5815
    POJ 1269
    HDU 5742
    HDU 4609
    fzu 1150 Farmer Bill's Problem
    fzu 1002 HangOver
    fzu 1001 Duplicate Pair
    fzu 1150 Farmer Bill's Problem
    fzu 1182 Argus 优先队列
  • 原文地址:https://www.cnblogs.com/jiayonghua/p/3965867.html
Copyright © 2011-2022 走看看