java多线程-Lock接口(将多线程共享资源锁定)

Java提供另外的机制用来同步代码块。它比synchronized关键字更加强大、灵活。Lockers在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作。它是基于Lock接口和实现它的类(如ReentrantLock)。
参考:http://www.jb51.net/article/45761.htm

Lock的优势:

  1. 它允许以一种更灵活的方式来构建synchronized块。使用synchronized关键字,你必须以结构化方式得到释放synchronized代码块的控制权。Lock接口允许你获得更复杂的结构来实现你的临界区。
  2. Lock 接口比synchronized关键字提供更多额外的功能。新功能之一是实现的tryLock()方法。这种方法试图获取锁的控制权并且如果它不能获取该锁,是因为其他线程在使用这个锁,它将返回这个锁。使用synchronized关键字,当线程A试图执行synchronized代码块,如果线程B正在执行它,那么线程A将阻塞直到线程B执行完synchronized代码块。使用锁,你可以执行tryLock()方法,这个方法返回一个 Boolean值表示,是否有其他线程正在运行这个锁所保护的代码。
  3. 当有多个读者和一个写者时,Lock接口允许读写操作分离。
    Lock接口比synchronized关键字提供更好的性能。

看一个示例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Lockers 在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,
 * 在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,
 * 从而保证数据的完整性。
 */
public class Lockers {
    public static void main(String[] args) throws Exception {
        Lockers.testLockTest();
    }

    public static void testLockTest() throws Exception {
        final LockTest lockTest = new LockTest();
        // 新建任务1,调用lockTest的addValue方法(计算)
        Runnable task1 = new Runnable() {
            public void run() {
                lockTest.addValue(55.55);
            }
        };
        // 新建任务2,调用lockTest的getValue方法(结果)
        Runnable task2 = new Runnable() {
            public void run() {
                System.out.println("value: " + lockTest.getValue());
            }
        };

        // 新建任务执行服务
        ExecutorService cachedService = Executors.newCachedThreadPool();
        Future future = null;
        // 同时执行任务1三次,由于addValue方法使用了锁机制,所以,实质上会顺序执行
        for (int i = 0; i < 3; i++) {
            future = cachedService.submit(task1);
        }
        // 等待最后一个任务1被执行完
        future.get();
        // 再执行任务2,输出结果
        future = cachedService.submit(task2);
        // 等待任务2执行完后,关闭任务执行服务
        future.get();
        cachedService.shutdownNow();
    }

    /**
     * 测试Lock的使用。在方法中使用Lock,可以避免使用Synchronized关键字。
     */
    public static class LockTest {
        Lock lock = new ReentrantLock();    // 锁
        double value = 0d;                  // 值
        int addtimes = 0;

        /**
         * 增加value的值,该方法的操作分为2步,而且相互依赖,必须实现在一个事务中
         * 所以该方法必须同步,以前的做法是在方法声明中使用Synchronized关键字。
         */
        public void addValue(double v) {
            lock.lock();// 取得锁
            System.out.println("开始计算(取得锁),请稍候...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            this.value += v;
            this.addtimes++;

            System.out.println("计算结束(释放锁)!");
            lock.unlock();// 释放锁
        }

        public double getValue() {
            return this.value;
        }
    }

}

运行结果:

开始计算(取得锁),请稍候...
计算结束(释放锁)!
开始计算(取得锁),请稍候...
计算结束(释放锁)!
开始计算(取得锁),请稍候...
计算结束(释放锁)!
value: 166.64999999999998

你可能感兴趣的:(并发)