不等待同步部分被占用

时间:2016-07-30 07:31:27

标签: java multithreading

我在syncCmd函数中有同步块:

public Object Sync = new Object();
public void syncCmd(String controlCmd) {
    synchronized(Sync) {

        ...
    }
} 

如果一个线程占用Sync并完成其工作,我需要添加一些逻辑。在这种情况下,我想向系统报告"too busy"而不是排队。了解某人是否已占用Sync部分的最佳方式是什么?如何知道本节中有多少线程在等待?一切都在Java 1.4.

4 个答案:

答案 0 :(得分:2)

查看Lock界面及其实现ReentrantLock。它允许您使用tryLock()方法,包括允许在资源已被锁定时等待一段时间的变体:

private  ReentrantLock lock = new ReentrantLock();

public void syncCmd(String controlCmd) {
    if (lock.tryLock()) {
        try {
            // Use your synchronized resource here
        } finally {
            lock.unlock();
        }
    } else {
        // Failed to lock
    }
}
遗憾的是,Java 1.4没有java.util.concurrency包,我认为你最好的选择是通过synchronized和双重检查来实现相同的逻辑:

public class Lock {
    private final Object lock = new Object();
    private volatile boolean locked = false;

    public boolean tryLock() {
        if (!locked) {
            synchronized (lock) {
                if (!locked) {
                    locked = true;
                    return true;
                }
            }
        }
        return false;
    }

    public void unlock() {
        synchronized (lock) {
            locked = false;
        }
    }
}

它不会像使用现代JVM中处理器指令支持的CAS循环的ReentrantLock一样快,但它可以完成这项工作。

此实现也不可重入,您可以扩展它以跟踪锁定线程并在需要重入时锁定计数。

重要更新: @Stephen C非常清楚Java 1.4中的double check is broken,并始终牢记这一点。但是有例外。例如,短基元类型。所以,我认为它将适用于这种特殊情况。有关详细信息,请查看"Double-Checked Locking is Broken" Declaration

答案 1 :(得分:1)

同步块/方法和原始互斥体在Java中无法做到这一点。

但是如果您使用Lock代替javadoc),则可以使用tryLock从不阻止或仅在有限时间内阻止。

示例:

 Lock l = new ReentrantLock();
 if (l.tryLock()) {
     try {
       // access the resource protected by this lock
     } finally {
           l.unlock();
     }
 else {
     // report "too busy"
 }

但请注意,使用"尝试......最后"和一个明确的unlock()调用,以确保始终释放锁。 (与synchronized构造不同,它会自动为您处理。)

在Java 1.5之前,没有我在纯Java中知道的解决方案。这可能是本机代码欺骗,但我不知道如何。

您/您的管理层应该寻求在您的产品中放弃对Java 1.4的支持,以及从依赖于它的任何第三方产品迁移。许多年前,Java 1.5本身就是EOL。实际上,Java 1.8之前的所有版本都已经过EOL& d;请参阅Oracle Java SE Support Roadmap文档。

答案 2 :(得分:1)

上面的两个答案谈到java.util.concurrent.locks.ReentrantLock,但它在Java 1.4中不存在。

太糟糕了,难过?

没有!如果系统库和第三方库没有按您的要求提供,请自行编写!

以下代码可以满足您的要求,而且完全没有。我个人不会在没有首先添加一些可以使它更有用,更可测试,更重要的是更加万无一失的功能的情况下使用它。

我只是提供给你作为开始的地方的一个例子。

public class ExtremelySimplisticNonReentrantLock {
    boolean isLocked = false;

    /**
     * @return true if the lock was acquired, false otherwise.
     */
    public synchronized boolean tryToAcquire() {
        if (isLocked) {
            return false;
        }
        isLocked = true;
        return true;
    }

    public synchronized void release() {
        lsLocked = false;
    }
}

分享并享受!

答案 3 :(得分:0)

试试这个(两个类 - Executor和Tracker):

执行人:

package com.example.so.jdk1_4.synch;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;


/**
 * <p> For http://stackoverflow.com/questions/38671520/not-wait-in-case-synchronized-section-is-occupied </p>
 * @author Ravindra HV
 */
public class InUseExample {

    public synchronized void execute(String command) {

        InUseTracker.obtainClassInstance().setInuse(true);

        try {
            System.out.println("Executing :"+command);
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }// do work

        InUseTracker.obtainClassInstance().setInuse(false);
    }


    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("Start :"+new Date());
        testInUseExample();
        System.out.println("Final wait count :"+InUseTracker.obtainClassInstance().waitCount());
        System.out.println("End :"+new Date());
    }


    private static void testInUseExample() {
        final InUseExample inUseExample = new InUseExample();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {

                try {
                    InUseTracker.obtainClassInstance().incrementWaitCount();
                    while(true) {
                        if( InUseTracker.obtainClassInstance().isInuse() == false ) { // reduces the chances of this thread going to a block mode..
                            inUseExample.execute(Thread.currentThread().getName());
                            break;
                        }
                        else {
                            try {
                                Random random = new Random();
                                String message = Thread.currentThread().getName()+" - block in use by :"+InUseTracker.obtainClassInstance().getInUseBy();
                                message = message+" "+". Wait Count :"+InUseTracker.obtainClassInstance().waitCount();
                                System.out.println(message);
                                Thread.sleep(random.nextInt(1000));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    InUseTracker.obtainClassInstance().decrementWaitCount();
                }

            }
        };

        int threadCount = 10;
        List<Thread> threadPoolTemp = new ArrayList<Thread>();
        for(int i=0;i<threadCount;i++) {
            Thread thread = new Thread(runnable);
            threadPoolTemp.add(thread);
        }

        for (Thread thread : threadPoolTemp) {
            thread.start();
        }

        for (Thread thread : threadPoolTemp) {
            try {
                thread.join(); // wait until all threads have executed..
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }



}

追踪器:

package com.example.so.jdk1_4.synch;

/**
 * <p> For http://stackoverflow.com/questions/38671520/not-wait-in-case-synchronized-section-is-occupied </p>
 * @author Ravindra HV
 */
public class InUseTracker {

    private boolean inuse;
    private int waitCount;
    private String inUseBy;

    private static InUseTracker DEFAULT_INSTANCE = new InUseTracker();

    private InUseTracker() {
    }

    public static InUseTracker obtainClassInstance() {
        return DEFAULT_INSTANCE;
    }


    public synchronized boolean isInuse() {
        return inuse;
    }

    public synchronized void setInuse(boolean inuse) {
        this.inuse = inuse;
        if(inuse) {
            setInUseBy(Thread.currentThread().getName());   
        }
        else {
            setInUseBy("");
        }

    }

    private void setInUseBy(String inUseBy) {
        this.inUseBy = inUseBy;
    }

    public synchronized String getInUseBy() {
        return inUseBy;
    }

    public synchronized void incrementWaitCount() {
        waitCount++;
    }

    public synchronized void decrementWaitCount() {
        waitCount--;
    }

    public synchronized int waitCount() {
        return waitCount;
    }

}
PS:猜猜你必须移动

InUseTracker.obtainClassInstance().setInuse(false);

在最终的if或酌情。