多线程表所有权

时间:2017-12-01 14:15:19

标签: java multithreading

通常可以从多个线程访问资源(读/写逻辑稍微复杂但不是问题的主题)。我必须创建一个方法owned,它使调用线程成为资源的所有者,并创建另一个方法notOwned,使所有线程都可以再次访问该资源。因此,在owned期间,只有调用线程才能接受资源,直到调用notOwned为止。

public class Example {
    public HashMap<String, Stuff> resources;
    public final ReentrantLock lock = new ReentrantLock();
    .....

    public void owned(String resource) {
        // TODO Auto-generated method stub
        resources.get(resource).lock.lock();
    }

    public void notOwned(String resource) {
        // TODO Auto-generated method stub
        resources.get(resource).lock.unlock();      
    }

    public void operation(String resource) {
        //the resource may or may be not owned (it is not owned all the time, as I said)
        boolean own = true;
        while (own) {
            own = ((resources.get(resource).lock.isHeldByCurrentThread() == false) && (resources.get(resource).lock.isLocked()));
        }
        //so now the resource is :
        //1. no longer owned, so all the threads can use it or
        //2. the current thread is the owner
        try {
          //let's consider this operation a writing type
          resources.get(resource).readLock.lock();
          tables.get(resources).information.add(resource);
       }  finally {resources.get(resource).readLock.unlock(); }
    }

等待资源不再被线程锁定是我提出的唯一解决方案......但是一致(意味着我想某些资源被锁定时,其他线程(所以不是所有者线程)仍在进行更改或者可能没有正确同步?我真的不知道)...它不一定是ReentrantLock但是必须围绕{{1}创建逻辑}和owned方法。

1 个答案:

答案 0 :(得分:0)

在Java中,线程在尝试获取监视器不可用(已锁定)的对象上的监视器(内部锁定对象)时进入等待状态。解锁此监视器后,将通知此监视器对象上等待的所有线程。这些线程为监视器完成,其中一个线程将再次获取监视器,其他线程将进入WAIT状态。

请根据您的代码查看以下示例,这是使用锁的正确方法。

public class Stuff {
    public final ReentrantLock resourceLock = new ReentrantLock();

    public void doStuff() {

        /*Once locked by one thread other threads would be waiting on this line in WAIT state
         * There's no need to check if it's already locked or not, it's done by Java, if it's locked then Thread goes in WAIT state
         * It's not busy waiting, thread wakes up only when notified by Java.
         */
        resourceLock.lock();
        try {
            /* <Critical Section> */
            //Now since resource is locked, it can be exclusively used by this thread

            /* </Critical Section> */
        } finally {
            //Once unlocked other threads would compete to acquire lock on: resourceLock.lock();
            resourceLock.unlock();
        }
    }
}

public class Example {
    public HashMap<String, Stuff> resources;

    /**
     * This is a utility method to just check if the resource is locked by current Thread, it performs no role in locking resource.
     */
    public boolean isOwned(String resource) {
        return ((resources.get(resource).lock.isHeldByCurrentThread() == false) && (resources.get(resource).lock.isLocked()))
    }

    public boolean isNotOwned(String resource) {
        return !isOwned();
    }

    public void operation(String resource) {
        Stuff stuff = resources.get(resource);
        stuff.doStuff();
    }
}

关于WAIT状态的一些有趣的事情

  1. 处于等待状态的线程必须放弃它所拥有的所有监视器。这意味着即使已经通知一台显示器,它也必须竞争它再次使用的所有显示器。
  2. 没有像在循环中检查锁定状态那样等待。
  3. 编辑:对于临时临界区,可以动态设置并行或非并行

    import java.util.HashMap;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicBoolean;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.ReentrantLock;
    
    class Stuff {
        public final ReentrantLock lock = new ReentrantLock();
        public AtomicBoolean isParallel = new AtomicBoolean(true);
        public AtomicInteger currentlyRunningThreadCount = new AtomicInteger();
        public CountDownLatch latch;
    
        public final static int MAX_WAIT_IN_SECONDS = 20;
    
        public void doStuff() throws Exception {
    
            if( !isParallel.get()) {
                System.out.println(threadName() + " Waiting");
    
                synchronized(this) {
                    if(latch == null) {
                        latch = new CountDownLatch(currentlyRunningThreadCount.get());/*Excluding the current thread with -1*/
                        System.out.println("latch count : " + latch.getCount() + " " + latch);
                    }
                }
                latch.await(MAX_WAIT_IN_SECONDS, TimeUnit.SECONDS);
    
                if( !lock.tryLock(MAX_WAIT_IN_SECONDS, TimeUnit.SECONDS)) {
                    throw new Exception("Could not acquire lock in specified time");
                }
    
                currentlyRunningThreadCount.incrementAndGet();
    
                System.out.println(threadName() + " Woke up");
            }
    
            try {
                /* <Critical Section> */
                for(int i = 0; i < 3; i++) {
                    System.out.println(threadName() + " \tRunning");
                    Thread.sleep(2000);
                }
                /* </Critical Section> */
            } finally {
    
                if(currentlyRunningThreadCount.get() > 0) {
                    currentlyRunningThreadCount.decrementAndGet();
                }
                if( !isParallel.get() && latch != null) {
                    latch.countDown();
                    System.out.println(threadName() + " down latch " + latch.getCount() + " " + latch);
                }
    
                if(lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
    
            System.out.println(threadName() + " Done do stuff");
        }
    
        public boolean isParallel() {
            return isParallel.get();
        }
    
        public void setParallel(boolean newValue) throws Exception {
            synchronized(this) {
                if(latch != null) {
                    latch.await();
                }
    
                latch = null;
            }
    
            isParallel.set(newValue);
        }
    
        public String threadName() {
            return Thread.currentThread().getName();
        }
    }
    
    public class Example {
        public static void main(String[] args) throws Exception {
            System.out.println("Started");
            Stuff stuff = new Stuff();
    
            Runnable run = () -> {
                try {
                    stuff.doStuff();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
    
            Thread t1 = new Thread(null, run, "t1");
            t1.start();
            Thread t2 = new Thread(null, run, "t2");
            t2.start();
    
            Thread.sleep(2000);
            stuff.setParallel(false);
            Thread t5 = new Thread(null, run, "t5");
            t5.start();
    
            Thread t6 = new Thread(null, run, "t6");
            t6.start();
    
            System.out.println("##### main exiting");
        }
    }
    
    Started
    t1  Running
    t2  Running
    t1  Running
    t2  Running
    t5 Waiting
    latch count : 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
    ##### main exiting
    t6 Waiting
    t5 Woke up
    t5  Running
    t2  Running
    t1  Running
    t5  Running
    t2 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
    t2 Done do stuff
    t1 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
    t1 Done do stuff
    t5  Running
    t5 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
    t5 Done do stuff
    t6 Woke up
    t6  Running
    t6  Running
    t6  Running
    t6 down latch 0 java.util.concurrent.CountDownLatch@61e7093d[Count = 0]
    t6 Done do stuff