org.unitime.timetable.onlinesectioning.MultiLock.java Source code

Java tutorial

Introduction

Here is the source code for org.unitime.timetable.onlinesectioning.MultiLock.java

Source

/*
 * Licensed to The Apereo Foundation under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 *
 * The Apereo Foundation licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
*/
package org.unitime.timetable.onlinesectioning;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cpsolver.ifs.util.ToolBox;

/**
 * @author Tomas Muller
 */
public class MultiLock {
    private Log iLog = LogFactory.getLog(MultiLock.class);
    private Lock iLock = new ReentrantLock();
    private Condition iAllLocked = null;
    private Map<Long, Condition> iIndividualLocks = new HashMap<Long, Condition>();

    public MultiLock() {
        iLog = LogFactory.getLog(MultiLock.class.getName() + ".lock");
    }

    public MultiLock(AcademicSessionInfo session) {
        iLog = LogFactory.getLog(MultiLock.class.getName() + ".lock[" + session.toCompactString() + "]");
    }

    private Condition hasLock(Collection<Long> ids) {
        if (iAllLocked != null)
            return iAllLocked;
        for (Long id : ids) {
            Condition c = iIndividualLocks.get(id);
            if (c != null)
                return c;
        }
        return null;
    }

    public Unlock lock(Long... ids) {
        List<Long> list = new ArrayList<Long>(ids.length);
        for (Long id : ids)
            list.add(id);
        return lock(list);
    }

    public UnlockAll lockAll() {
        iLock.lock();
        try {
            iLog.debug("Locking all ...");
            while (iAllLocked != null)
                iAllLocked.awaitUninterruptibly();
            iAllLocked = iLock.newCondition();
            while (!iIndividualLocks.isEmpty()) {
                Condition otherCondition = iIndividualLocks.values().iterator().next();
                otherCondition.awaitUninterruptibly();
            }
            iLog.debug("Locked: all");
            return new UnlockAll();
        } finally {
            iLock.unlock();
        }
    }

    public void unlockAll() {
        iLock.lock();
        try {
            iLog.debug("Unlocking all ...");
            Condition allLocked = iAllLocked;
            iAllLocked = null;
            allLocked.signalAll();
            iLog.debug("Unlocked: all");
        } finally {
            iLock.unlock();
        }
    }

    public Unlock lock(Collection<Long> ids) {
        iLock.lock();
        try {
            if (ids == null || ids.isEmpty())
                return new Unlock(ids);
            iLog.debug("Locking " + ids + " ...");
            Condition otherCondition = null;
            while ((otherCondition = hasLock(ids)) != null)
                otherCondition.awaitUninterruptibly();
            Condition myCondition = iLock.newCondition();
            for (Long id : ids)
                iIndividualLocks.put(id, myCondition);
            iLog.debug("Locked: " + ids);
            return new Unlock(ids);
        } finally {
            iLock.unlock();
        }
    }

    private void unlock(Collection<Long> ids) {
        iLock.lock();
        try {
            if (ids == null || ids.isEmpty())
                return;
            iLog.debug("Unlocking " + ids + " ...");
            Condition myCondition = null;
            for (Long id : ids)
                myCondition = iIndividualLocks.remove(id);
            if (myCondition != null)
                myCondition.signalAll();
            iLog.debug("Unlocked: " + ids);
        } finally {
            iLock.unlock();
        }
    }

    public Set<Long> locked() {
        iLock.lock();
        try {
            return new TreeSet<Long>(iIndividualLocks.keySet());
        } finally {
            iLock.unlock();
        }
    }

    public boolean isLocked(Long id) {
        iLock.lock();
        try {
            return iIndividualLocks.containsKey(id);
        } finally {
            iLock.unlock();
        }
    }

    public class Unlock implements OnlineSectioningServer.Lock {
        private Collection<Long> iIds;

        private Unlock(Collection<Long> ids) {
            iIds = ids;
        }

        public void release() {
            unlock(iIds);
        }
    }

    public class UnlockAll implements OnlineSectioningServer.Lock {

        private UnlockAll() {
        }

        public void release() {
            unlockAll();
        }
    }

    public static void main(String[] args) {
        try {
            final MultiLock lock = new MultiLock();
            for (int i = 1; i <= 1000; i++) {
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            while (true) {
                                int nrCourses = 2 + ToolBox.random(9);
                                Set<Long> courses = new HashSet<Long>();
                                String s = "";
                                for (int i = 0; i < nrCourses; i++) {
                                    long courseId;
                                    do {
                                        courseId = ToolBox.random(10000);
                                    } while (!courses.add(courseId));
                                    s += (i > 0 ? ", " : "") + courseId;
                                }
                                System.out.println(Thread.currentThread().getName() + "Locking: [" + s + "]");
                                Unlock l = lock.lock(courses);
                                System.out.println(Thread.currentThread().getName() + "Locked: [" + s + "]");
                                try {
                                    Thread.sleep(ToolBox.random(1000));
                                } catch (InterruptedException e) {
                                }
                                System.out.println(Thread.currentThread().getName() + "Unlocking: [" + s + "]");
                                l.release();
                                System.out.println(Thread.currentThread().getName() + "Unlocked: [" + s + "]");
                            }
                        } catch (Exception e) {
                            System.err.println(Thread.currentThread().getName() + e.getMessage());
                            e.printStackTrace();
                        }
                    }
                });
                t.setName("[T" + i + "]: ");
                t.start();
            }
            for (int i = 1; i <= 3; i++) {
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            while (true) {
                                try {
                                    Thread.sleep(ToolBox.random(5000));
                                } catch (InterruptedException e) {
                                }
                                System.out.println(Thread.currentThread().getName() + "Locking all...");
                                lock.lockAll();
                                System.out.println(Thread.currentThread().getName() + "All locked.");
                                try {
                                    Thread.sleep(ToolBox.random(1000));
                                } catch (InterruptedException e) {
                                }
                                System.out.println(Thread.currentThread().getName() + "Unlocking all.");
                                lock.unlockAll();
                                System.out.println(Thread.currentThread().getName() + "All unlocked.");
                            }
                        } catch (Exception e) {
                            System.err.println(Thread.currentThread().getName() + e.getMessage());
                            e.printStackTrace();
                        }
                    }
                });
                t.setName("[A" + i + "]: ");
                t.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}