线程锁技术

来源:互联网 发布:华兴资本知乎 编辑:程序博客网 时间:2024/06/10 17:15
 Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,他们必须用同一个Lock对象,锁是上在代表要操作的资源的类的内部方法中,而不是线程代码中。
import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; public class LockTest {    public static void main(String[] args) {      new LockTest().init();   }     public void init(){      Outputer outputer = new Outputer();      new Thread(new Runnable(){          @Override         public void run() {            while(true){                try {                   Thread.sleep(10);                } catch (InterruptedException e) {                   e.printStackTrace();                }                outputer.output("zhangxiaoxiang");            }         }              }).start();           new Thread(new Runnable(){          @Override         public void run() {            while(true){                try {                   Thread.sleep(10);                } catch (InterruptedException e) {                   e.printStackTrace();                }                outputer.output("liwenfei");            }         }              }).start();   }     /**    * 会出现线程安全的问题    *    */ /* class Outputer{      public void output(String name){         int len = name.length();         for(int i=0; i<len; i++){            System.out.print(name.charAt(i));         }         System.out.println();//换行      }   }*/     static class Outputer{      Lock lock = new ReentrantLock();      public void output(String name){         int len = name.length();         lock.lock();         try{//使用try是确保里边的代码不管有没有出错,最后都要打开锁            for(int i=0; i<len; i++){                System.out.print(name.charAt(i));            }            System.out.println();//换行         }finally{            lock.unlock();         }      }           /**       * 方法二:把要同步的代码所在方法全部同步       * 在方法上使用synchronized后不要在内部再使用synchronized,不然很容易出现死锁       */      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();//换行      }           /**       * 如果这个同步方法是static的,那么为了确保不管谁调用同步方法,锁对象是同一个,       * 那么锁只能为当前类的字节码对象,即Outputer.class       * @param name       */      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();//换行      }   }  }
Lock分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读数据,那就上写锁。总之读的时候上读锁,写的时候上写锁。提高性能。
import java.util.Random;import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockTest {public static void main(String[] args) {final Queue3 q3 = new Queue3();for (int i = 0; i < 3; i++) {new Thread() {@Overridepublic void run() {while (true) {q3.get();}}}.start();new Thread() {public void run() {while (true) {q3.put(new Random().nextInt(10000));}};}.start();}}}class Queue3 {private Object data = null; // 共享数据,只能又一个线程能写该数据,但是可以有多个线程可以读private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();public void get() {rwl.readLock().lock();try {System.out.println(Thread.currentThread().getName() + " be ready to read data!");Thread.sleep((long) (Math.random() * 1000));System.out.println(Thread.currentThread().getName() + " hava read data : " + data);} catch (Exception e) {e.printStackTrace();} finally {rwl.readLock().unlock(); // 使用finally不管出现什么意外,一定要将锁释放掉}}public void put(Object data) {rwl.writeLock().lock();try {System.out.println(Thread.currentThread().getName() + " be ready to write data!");Thread.sleep((long) (Math.random() * 1000));this.data = data;System.out.println(Thread.currentThread().getName() + " hava writed data : " + data);} catch (Exception e) {e.printStackTrace();} finally {rwl.writeLock().unlock();}}}

在jdk api java.util.concurrent.locks.ReentrantReadWriteLock类中有个缓存器设计的伪代码示例:
 class CachedData {   Object data;   volatile boolean cacheValid;   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();   void processCachedData() {     rwl.readLock().lock();     if (!cacheValid) {        // Must release read lock before acquiring write lock        rwl.readLock().unlock();        rwl.writeLock().lock();        // Recheck state because another thread might have acquired        //   write lock and changed state before we did.        if (!cacheValid) {          data = ...          cacheValid = true;        }        // Downgrade by acquiring read lock before releasing write lock        rwl.readLock().lock();        rwl.writeLock().unlock(); // Unlock write, still hold read     }     use(data);     rwl.readLock().unlock();   } }

缓存的思想:

 












原创粉丝点击