新的起点 新的开始

快乐生活 !

(转)Java 5.0多线程编程(3)

Lock 接口

ReentrantLock Lock 的具体类, Lock 提供了以下一些方法:

  • lock(): 请求锁定,如果锁已被别的线程锁定,调用此方法的线程被阻断进入等待状态。
  • tryLock() :如果锁没被别的线程锁定,进入锁定状态,并返回 true 。若锁已被锁定,返回 false ,不进入等待状态。此方法还可带时间参数,如果锁在方法执行时已被锁定,线程将继续等待规定的时间,若还不行才返回 false
  • unlock() :取消锁定,需要注意的是 Lock 不会自动取消,编程时必须手动解锁。

代码:

// 生成一个锁

Lock lock = new ReentrantLock();

public void accessProtectedResource() {

  lock.lock(); // 取得锁定

  try {

    // 对共享资源进行操作

  } finally {

    // 一定记着把锁取消掉,锁本身是不会自动解锁的

    lock.unlock();

  }

}

ReadWriteLock 接口

   为了提高效率有些共享资源允许同时进行多个读的操作,但只允许一个写的操作,比如一个文件,只要其内容不变可以让多个线程同时读,不必做排他的锁定,排他的锁定只有在写的时候需要,以保证别的线程不会看到数据不完整的文件。 ReadWriteLock 可满足这种需要。 ReadWriteLock 内置两个 Lock ,一个是读的 Lock ,一个是写的 Lock 。多个线程可同时得到读的 Lock ,但只有一个线程能得到写的 Lock ,而且写的 Lock 被锁定后,任何线程都不能得到 Lock ReadWriteLock 提供的方法有:

  • readLock(): 返回一个读的 lock
  • writeLock(): 返回一个写的 lock, lock 是排他的。

ReadWriteLock 的例子:

public class FileOperator{

      // 初始化一个 ReadWriteLock

      ReadWriteLock lock = new ReentrantReadWriteLock();

public String read() {

      // 得到 readLock 并锁定

            Lock readLock = lock.readLock();

            readLock.lock();

            try {

                  // 做读的工作

                  return "Read something";

            } finally {

                 readLock.unlock();

            }

      }

     

public void write(String content) {

      // 得到 writeLock 并锁定

            Lock writeLock = lock.writeLock();

            writeLock.lock();

            try {

                  // 做读的工作

            } finally {

                 writeLock.unlock();

            }

      }

}

 

   需要注意的是 ReadWriteLock 提供了一个高效的锁定机理,但最终程序的运行效率是和程序的设计息息相关的,比如说如果读的线程和写的线程同时在等待,要考虑是先发放读的 lock 还是先发放写的 lock 。如果写发生的频率不高,而且快,可以考虑先给写的 lock 。还要考虑的问题是如果一个写正在等待读完成,此时一个新的读进来,是否要给这个新的读发锁,如果发了,可能导致写的线程等很久。等等此类问题在编程时都要给予充分的考虑。

Condition 接口:

   有时候线程取得 lock 后需要在一定条件下才能做某些工作,比如说经典的 Producer Consumer 问题, Consumer 必须在篮子里有苹果的时候才能吃苹果,否则它必须暂时放弃对篮子的锁定,等到 Producer 往篮子里放了苹果后再去拿来吃。而 Producer 必须等到篮子空了才能往里放苹果,否则它也需要暂时解锁等 Consumer 把苹果吃了才能往篮子里放苹果。在 Java 5.0 以前,这种功能是由 Object 类的 wait(), notify() notifyAll() 等方法实现的,在 5.0 里面,这些功能集中到了 Condition 这个接口来实现, Condition 提供以下方法:

  • await() :使调用此方法的线程放弃锁定,进入睡眠直到被打断或被唤醒。
  • signal(): 唤醒一个等待的线程
  • signalAll() :唤醒所有等待的线程

Condition 的例子:

public class Basket {     

Lock lock = new ReentrantLock();

// 产生 Condition 对象

     Condition produced = lock.newCondition();

     Condition consumed = lock.newCondition();

     boolean available = false;

     

     public void produce() throws InterruptedException {

           lock.lock();

           try {

                 if(available){

                    consumed.await(); // 放弃 lock 进入睡眠  

                 }

                 /* 生产苹果 */

                 System.out.println("Apple produced.");

                 available = true;

                 produced.signal(); // 发信号唤醒等待这个 Condition 的线程

           } finally {

                 lock.unlock();

           }

     }

    

     public void consume() throws InterruptedException {

           lock.lock();

           try {

                 if(!available){

                       produced.await();// 放弃 lock 进入睡眠  

                 }

                 /* 吃苹果 */

                 System.out.println("Apple consumed.");

                 available = false;

                 consumed.signal();// 发信号唤醒等待这个 Condition 的线程

           } finally {

                 lock.unlock();

           }

     }     

}

ConditionTester:

public class ConditionTester {

     

      public static void main(String[] args) throws InterruptedException{

final Basket basket = new Basket();

// 定义一个 producer

            Runnable producer = new Runnable() {

                  public void run() {

                        try {

                              basket.produce();

                        } catch (InterruptedException ex) {

                              ex.printStackTrace();

                        }

                  }

};

// 定义一个 consumer

            Runnable consumer = new Runnable() {

                  public void run() {

                        try {

                              basket.consume();

                        } catch (InterruptedException ex) {

                              ex.printStackTrace();

                        }

                  }

};

// 各产生 10 consumer producer

            ExecutorService service = Executors.newCachedThreadPool();

            for(int i=0; i < 10; i++)

                  service.submit(consumer);

            Thread.sleep(2000);

            for(int i=0; i<10; i++)

                  service.submit(producer);

            service.shutdown();

      }     

}

5: Synchronizer:同步装置

   Java 5.0 里新加了 4 个协调线程间进程的同步装置,它们分别是 Semaphore, CountDownLatch, CyclicBarrier Exchanger.

Semaphore:

   用来管理一个资源池的工具, Semaphore 可以看成是个通行证,线程要想从资源池拿到资源必须先拿到通行证, Semaphore 提供的通行证数量和资源池的大小一致。如果线程暂时拿不到通行证,线程就会被阻断进入等待状态。以下是一个例子:

public class Pool {

      ArrayList pool = null;

      Semaphore pass = null;

      public Pool(int size){

            // 初始化资源池

            pool = new ArrayList();

            for(int i=0; i

                  pool.add("Resource "+i);

            }

            //Semaphore 的大小和资源池的大小一致

            pass = new Semaphore(size);

      }

      public String get() throws InterruptedException{

            // 获取通行证 , 只有得到通行证后才能得到资源

            pass.acquire();

            return getResource();

      }

      public void put(String resource){

            // 归还通行证,并归还资源

            pass.release();

            releaseResource(resource);

      }

     private synchronized String getResource() {

            String result = pool.get(0);

            pool.remove(0);

            System.out.println("Give out "+result);

            return result;

      }

      private synchronized void releaseResource(String resource) {

            System.out.println("return "+resource);

            pool.add(resource);

      }

}

SemaphoreTest:

public class SemaphoreTest {

      public static void main(String[] args){

            final Pool aPool = new Pool(2);

            Runnable worker = new Runnable() {

                  public void run() {

                        String resource = null;

                        try {

                              // 取得 resource

                              resource = aPool.get();

                        } catch (InterruptedException ex) {

                              ex.printStackTrace();

                        }

                        // resource 做工作

                        System.out.println("I worked on "+resource);

                        // 归还 resource

                        aPool.put(resource);

                  }

            };

            ExecutorService service = Executors.newCachedThreadPool();

            for(int i=0; i<20; i++){

                  service.submit(worker);

            }

            service.shutdown();

      }    

}


posted on 2007-03-26 14:31 advincenting 阅读(255) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 

公告

Locations of visitors to this page

导航

<2007年3月>
25262728123
45678910
11121314151617
18192021222324
25262728293031
1234567

统计

常用链接

留言簿(13)

随笔分类(71)

随笔档案(179)

文章档案(13)

新闻分类

IT人的英语学习网站

JAVA站点

优秀个人博客链接

官网学习站点

生活工作站点

最新随笔

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜