It is a homework assignment. I have two files which were already given. The Client class
and the SharedValues Interface
. Here is the description:
I need to write a class
(resource handler) which contains static interfaces
and manage "n" number of resource allocation and its scheduling for "k" number of clients. there must be only two operations
for the clients. Reading and writing
with no deadlock and no starvation
. If one resource is allocated for writing then other clients can't have it for any other purpose. If the resource is allocated for reading then only readers can get it, writers not. A key can make the resources free it got for the allocation. The references of resources are represented by String
(names).
The Resource Handler
must contain two interfaces
for the clients. getLock()
and releaseLock()
. The required argument of the getLock()
interface is an object (Set<String>)
in which the names of the resources and the desired operations (boolean: true - writing, false - reading)
are placed, the return value is an identifier (long)
. Until the resource handler can't give the requested resources to the cleint, the resource handler should be blocked the current client on the getLock()
call. It will be unblock again when the requested resources are available for the given operation. The return value of the releaseLock()
is void
, its required argument is an identifier what it got at the getLock()
call. The clients are requesting the lock/release of resources as a subsets of resources from the resource handler class (through the getLock()
interface) and the clients are releasing the resources by the received identifier. (through the releaseLock()
interface).
I am not pro in Java and i have only a little experience in multithreading. Please take into account.
Given the following class and interface:
SharedValues Interface
public interface SharedValues
{
//resources
public final static String[] RESOURCE_LIST = new String[]{ "a", "b", "c", "d", "e", "f", "g", "h" };
//constant of the client's writing method type
public final static boolean WRITE_METHOD = true;
//constant of the client's reading method type
public final static boolean READ_METHOD = false;
//constant for the number of clients
public final static int CLIENTNUM = 5;
//minimum wait time of the client
public final static int CLIENT_HOLD_MINIMUM = 1000;
//maximum wait time difference of the client
public final static int CLIENT_HOLD_DIFF = 1000;
//time limit of the clients
public final static int RUNTIME = 20000;
}
Client class
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.ArrayList;
//start and implementation of the client
public class Client extends Thread implements SharedValues
{
//used random for creating clients
private static Random mRandom = new Random();
//for stoping flag
private boolean mRunning = true;
//used method in client
private boolean mMethod = true;
//the clients want to lock these resources
private Set<String> mNeededRes = new HashSet<String>();
//received identifier for the releasing cleint's resources
private long mLockID = -1;
//client's logging name
private String mLogName = null;
//client's constructor
public Client( String[] xResList, boolean xMethod, int xClientID )
{
super( "Client_" + xClientID );
mLogName = "Client_" + xClientID;
mMethod = xMethod;
for ( int i = 0; i < xResList.length; i++ )
{
mNeededRes.add( xResList[ i ] );
}
}
//interface for logging
private void log( String xMessage )
{
System.out.println( new Date() + " " + mLogName + ": " + xMessage );
}
//holding resources or sleeping
private synchronized void holdResources()
{
if ( !mRunning )
{
return;
}
//sleeping a value what is in the intervall
try
{
wait( mRandom.nextInt( CLIENT_HOLD_DIFF ) & CLIENT_HOLD_MINIMUM );
}
catch ( InterruptedException e )
{
log( "Error: Resource allocating interrupted" );
}
}
//for stopping interface
public synchronized void stopRunning() throws Exception
{
//changing the flag and interrupting the sleep if it has
if ( mRunning )
{
mRunning = false;
wait();
}
else
{
log( "Error: the client has already stopped!" );
}
}
//Overloading thread method
public void run()
{
log( "Started." );
while ( mRunning )
{
log( ( ( mMethod == WRITE_METHOD ) ? "Writing" : "Reading" ) + " requested resources: "
+ toSortedSet( mNeededRes ) );
final long startTime = System.currentTimeMillis();
mLockID = ResHandler.getLock( mNeededRes, mMethod );
final long elapsed = System.currentTimeMillis() - startTime;
log( ( ( mMethod == WRITE_METHOD ) ? "Writing" : "Reading" ) + " received resources (" + elapsed
+ " ms): " + toSortedSet( mNeededRes ) + ". Lock: " + mLockID );
holdResources();
ResHandler.releaseLock( mLockID );
holdResources();
}
log( "Stopped." );
}
//creating clients
private static Client createClient( int xClientID )
{
final int resNum = mRandom.nextInt( RESOURCE_LIST.length ) + 1;
//randomly take out one of all resources
final ArrayList<String> selectedRes = new ArrayList<String>( Arrays.asList( RESOURCE_LIST ) );
for ( int i = 0; i < ( RESOURCE_LIST.length - resNum ); i++ )
{
final int chosenRes = mRandom.nextInt( selectedRes.size() );
selectedRes.remove( chosenRes );
}
final boolean method = mRandom.nextInt( 5 ) <= 2;
return new Client( ( String[] ) selectedRes.toArray( new String[]{} ), method, xClientID );
}
//auxiliary interface for elements of subset, we can do sorted logging
private String toSortedSet( Set<String> xSet )
{
final StringBuffer tmpSB = new StringBuffer( "{ " );
final String[] sortedRes = ( String[] ) xSet.toArray( new String[]{} );
Arrays.sort( sortedRes );
for ( int i = 0; i < sortedRes.length; i++ )
{
tmpSB.append( sortedRes[ i ] ).append( ", " );
}
tmpSB.setLength( tmpSB.length() - 2 );
tmpSB.append( " }" );
return tmpSB.toString();
}
public static void main( String[] args ) throws Exception
{
//keep the clients for stop
final Client[] clientArr = new Client[ CLIENTNUM ];
for ( int i = 0; i < clientArr.length; i++ )
{
clientArr[ i ] = createClient( i );
clientArr[ i ].start();
//the clients do not start at the same time
try
{
Thread.sleep( mRandom.nextInt( CLIENT_HOLD_MINIMUM ) );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
//sleeping the running time of clients
try
{
Thread.sleep( RUNTIME );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
//stopping cleints
for ( int i = 0; i < clientArr.length; i++ )
{
clientArr[ i ].stopRunning();
try
{
clientArr[ i ].join();
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
}
}
I wrote this so far. I see the client log where the Lock is always 0 and the elapsed time 0ms but I do not know why.
Resource Handler class
import java.util.Set;
class ResHandler {
private static long identifier;
public static long getLock(Set<String> mNeededRes, boolean mMethod) {
return identifier;
}
public static void releaseLock(long mLockID) {
}
This is the Output:
Wed Oct 09 04:42:25 CEST 2013 Client_0: Started.
Wed Oct 09 04:42:25 CEST 2013 Client_0: Writing requested resources: { b, c, d, g, h }
Wed Oct 09 04:42:25 CEST 2013 Client_0: Writing received resources (4 ms): { b, c, d, g, h }. Lock: 0
Wed Oct 09 04:42:26 CEST 2013 Client_1: Started.
Wed Oct 09 04:42:26 CEST 2013 Client_1: Writing requested resources: { a, b, c, d, e, f, g, h }
Wed Oct 09 04:42:26 CEST 2013 Client_1: Writing received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:26 CEST 2013 Client_0: Writing requested resources: { b, c, d, g, h }
Wed Oct 09 04:42:26 CEST 2013 Client_0: Writing received resources (0 ms): { b, c, d, g, h }. Lock: 0
Wed Oct 09 04:42:26 CEST 2013 Client_1: Writing requested resources: { a, b, c, d, e, f, g, h }
Wed Oct 09 04:42:26 CEST 2013 Client_1: Writing received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:26 CEST 2013 Client_2: Started.
Wed Oct 09 04:42:26 CEST 2013 Client_2: Writing requested resources: { a, b, d, e, f, g, h }
Wed Oct 09 04:42:26 CEST 2013 Client_2: Writing received resourcesk (0 ms): { a, b, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:27 CEST 2013 Client_0: Writing requested resources: { b, c, d, g, h }
Wed Oct 09 04:42:27 CEST 2013 Client_0: Writing received resources (0 ms): { b, c, d, g, h }. Lock: 0
Wed Oct 09 04:42:27 CEST 2013 Client_3: Started.
Wed Oct 09 04:42:27 CEST 2013 Client_3: Reading requested resources: { a, b, c, d, e, f, g, h }
Wed Oct 09 04:42:27 CEST 2013 Client_3: Reading received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:27 CEST 2013 Client_4: Started.
Wed Oct 09 04:42:27 CEST 2013 Client_4: Reading requested resources: { f, h }
Wed Oct 09 04:42:27 CEST 2013 Client_4: Reading received resources (0 ms): { f, h }. Lock: 0
Wed Oct 09 04:42:27 CEST 2013 Client_1: Writing requested resources: { a, b, c, d, e, f, g, h }
Wed Oct 09 04:42:27 CEST 2013 Client_1: Writing received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:28 CEST 2013 Client_0: Writing requested resources: { b, c, d, g, h }
Wed Oct 09 04:42:28 CEST 2013 Client_0: Writing received resources (0 ms): { b, c, d, g, h }. Lock: 0
Wed Oct 09 04:42:28 CEST 2013 Client_4: Reading requested resources: { f, h }
Wed Oct 09 04:42:28 CEST 2013 Client_4: Reading received resources (0 ms): { f, h }. Lock: 0
Wed Oct 09 04:42:28 CEST 2013 Client_3: Reading requested resources: { a, b, c, d, e, f, g, h }
Wed Oct 09 04:42:28 CEST 2013 Client_3: Reading received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:28 CEST 2013 Client_2: Writing requested resources: { a, b, d, e, f, g, h }
Wed Oct 09 04:42:28 CEST 2013 Client_2: Writing received resources (0 ms): { a, b, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:28 CEST 2013 Client_3: Reading requested resources: { a, b, c, d, e, f, g, h }
Wed Oct 09 04:42:28 CEST 2013 Client_3: Reading received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:29 CEST 2013 Client_1: Writing requested resources: { a, b, c, d, e, f, g, h }
Wed Oct 09 04:42:29 CEST 2013 Client_1: Writing received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:29 CEST 2013 Client_2: Writing requested resources: { a, b, d, e, f, g, h }
Wed Oct 09 04:42:29 CEST 2013 Client_2: Writing received resources (0 ms): { a, b, d, e, f, g, h }. Lock: 0
Wed Oct 09 04:42:29 CEST 2013 Client_4: Reading requested resources: { f, h }
Wed Oct 09 04:42:29 CEST 2013 Client_4: Reading received resources (0 ms): { f, h }. Lock: 0
Wed Oct 09 04:42:29 CEST 2013 Client_0: Writing requested resources: { b, c, d, g, h }
Wed Oct 09 04:42:29 CEST 2013 Client_0: Writing received resources (0 ms): { b, c, d, g, h }. Lock: 0
. . .
I found a half solution on the internet: Resource manager with ReentrantLocks
public class ResHandler {
//ID-s of the granted resource lists
private static long lockNum = 0;
//Resources are identified by strings, each client has a list of demanded resources
//we store these when granted, along with an ID
private static ConcurrentHashMap<Long, Set<String>> usedResources
= new ConcurrentHashMap<Long, Set<String>>();
//We store a lock for each resource
private static ConcurrentHashMap<String, ReentrantReadWriteLock> resources
= new ConcurrentHashMap<String, ReentrantReadWriteLock>();
//Filling our resources map with the resources and their locks
static {
for (int i = 0; i < SharedValues.RESOURCE_LIST.length; ++i) {
String res = SharedValues.RESOURCE_LIST[i];
//Fair reentrant lock
ReentrantReadWriteLock lc = new ReentrantReadWriteLock(true);
resources.put(res, lc);
}
}
//We get a set of the required resources and the type of lock we have to use
public static long getLock(Set<String> mNeededRes, boolean mMethod) {
//!!!
if (mMethod == SharedValues.READ_METHOD) {
//We try to get the required resources
for (String mn : mNeededRes)
resources.get(mn).readLock().lock();
//After grandted, we put them in the usedResources map
++lockNum;
usedResources.put(lockNum, mNeededRes);
return lockNum;
}
//Same thing, but with write locks
else {
for (String mn : mNeededRes)
resources.get(mn).writeLock().lock();
++lockNum;
usedResources.put(lockNum, mNeededRes);
return lockNum;
}
}
//Releasing a set of locks by the set's ID
public static void releaseLock(long mLockID) {
if (!usedResources.containsKey(mLockID)) {
System.out.println("returned, no such key as: " + mLockID);
return;
}
Set<String> toBeReleased = usedResources.get(mLockID);
//Unlocking every lock from this set
for (String s : toBeReleased) {
if (resources.get(s).isWriteLockedByCurrentThread())
resources.get(s).writeLock().unlock();
else
resources.get(s).readLock().unlock();
}
//Deleting from the map
usedResources.remove(mLockID);
}
}
I tried this and the output was changed to this:
Fri Oct 11 10:14:40 CEST 2013 Client_0: Started.
Fri Oct 11 10:14:40 CEST 2013 Client_0: Reading requested resources: { b, c, h }
Fri Oct 11 10:14:40 CEST 2013 Client_0: Reading received resources (8 ms): { b, c, h }. Lock: 1
Fri Oct 11 10:14:40 CEST 2013 Client_1: Started.
Fri Oct 11 10:14:40 CEST 2013 Client_1: Reading requested resources: { a, b, c, d, f, g, h }
Fri Oct 11 10:14:40 CEST 2013 Client_1: Reading received resources (1 ms): { a, b, c, d, f, g, h }. Lock: 2
Fri Oct 11 10:14:40 CEST 2013 Client_2: Started.
Fri Oct 11 10:14:40 CEST 2013 Client_2: Reading requested resources: { a, b, d, e, f, g, h }
Fri Oct 11 10:14:40 CEST 2013 Client_2: Reading received resources (0 ms): { a, b, d, e, f, g, h }. Lock: 3
Fri Oct 11 10:14:40 CEST 2013 Client_2: Reading requested resources: { a, b, d, e, f, g, h }
Fri Oct 11 10:14:40 CEST 2013 Client_2: Reading received resources (0 ms): { a, b, d, e, f, g, h }. Lock: 4
Fri Oct 11 10:14:41 CEST 2013 Client_3: Started.
Fri Oct 11 10:14:41 CEST 2013 Client_3: Writing requested resources: { h }
Fri Oct 11 10:14:41 CEST 2013 Client_1: Reading requested resources: { a, b, c, d, f, g, h }
Fri Oct 11 10:14:41 CEST 2013 Client_0: Reading requested resources: { b, c, h }
Fri Oct 11 10:14:41 CEST 2013 Client_3: Writing received resources (303 ms): { h }. Lock: 5
Fri Oct 11 10:14:41 CEST 2013 Client_1: Reading received resources (293 ms): { a, b, c, d, f, g, h }. Lock: 6
Fri Oct 11 10:14:41 CEST 2013 Client_0: Reading received resources (171 ms): { b, c, h }. Lock: 7
Fri Oct 11 10:14:41 CEST 2013 Client_3: Writing requested resources: { h }
Fri Oct 11 10:14:41 CEST 2013 Client_4: Started.
Fri Oct 11 10:14:41 CEST 2013 Client_4: Reading requested resources: { a, b, c, d, e, f, g, h }
Fri Oct 11 10:14:42 CEST 2013 Client_3: Writing received resources (633 ms): { h }. Lock: 8
Fri Oct 11 10:14:42 CEST 2013 Client_2: Reading requested resources: { a, b, d, e, f, g, h }
Fri Oct 11 10:14:42 CEST 2013 Client_4: Reading received resources (819 ms): { a, b, c, d, e, f, g, h }. Lock: 9
Fri Oct 11 10:14:42 CEST 2013 Client_2: Reading received resources (163 ms): { a, b, d, e, f, g, h }. Lock: 10
Fri Oct 11 10:14:42 CEST 2013 Client_1: Reading requested resources: { a, b, c, d, f, g, h }
Fri Oct 11 10:14:42 CEST 2013 Client_1: Reading received resourcesk (0 ms): { a, b, c, d, f, g, h }. Lock: 11
Fri Oct 11 10:14:42 CEST 2013 Client_0: Reading requested resources: { b, c, h }
Fri Oct 11 10:14:42 CEST 2013 Client_0: Reading received resources (0 ms): { b, c, h }. Lock: 12
Fri Oct 11 10:14:42 CEST 2013 Client_3: Writing requested resources: { h }
Fri Oct 11 10:14:42 CEST 2013 Client_0: Reading requested resources: { b, c, h }
Fri Oct 11 10:14:43 CEST 2013 Client_1: Reading requested resources: { a, b, c, d, f, g, h }
Fri Oct 11 10:14:43 CEST 2013 Client_3: Writing received resources (447 ms): { h }. Lock: 13
Fri Oct 11 10:14:43 CEST 2013 Client_0: Reading received resources (504 ms): { b, c, h }. Lock: 14
Fri Oct 11 10:14:43 CEST 2013 Client_1: Reading received resources (210 ms): { a, b, c, d, f, g, h }. Lock: 15
Fri Oct 11 10:14:43 CEST 2013 Client_4: Reading requested resources: { a, b, c, d, e, f, g, h }
Fri Oct 11 10:14:43 CEST 2013 Client_4: Reading received resources (0 ms): { a, b, c, d, e, f, g, h }. Lock: 16
Fri Oct 11 10:14:43 CEST 2013 Client_2: Reading requested resources: { a, b, d, e, f, g, h }
Fri Oct 11 10:14:43 CEST 2013 Client_2: Reading received resources (0 ms): { a, b, d, e, f, g, h }. Lock: 17
Fri Oct 11 10:14:43 CEST 2013 Client_1: Reading requested resources: { a, b, c, d, f, g, h }
Fri Oct 11 10:14:43 CEST 2013 Client_1: Reading received resources (0 ms): { a, b, c, d, f, g, h }. Lock: 18
Fri Oct 11 10:14:44 CEST 2013 Client_3: Writing requested resources: { h }
Fri Oct 11 10:14:44 CEST 2013 Client_3: Writing received resources (152 ms): { h }. Lock: 19
Fri Oct 11 10:14:44 CEST 2013 Client_2: Reading requested resources: { a, b, d, e, f, g, h }
Fri Oct 11 10:14:44 CEST 2013 Client_0: Reading requested resources: { b, c, h }
Fri Oct 11 10:14:44 CEST 2013 Client_4: Reading requested resources: { a, b, c, d, e, f, g, h }
Fri Oct 11 10:14:44 CEST 2013 Client_1: Reading requested resources: { a, b, c, d, f, g, h }
Fri Oct 11 10:14:45 CEST 2013 Client_0: Reading received resources (504 ms): { b, c, h }. Lock: 21
Fri Oct 11 10:14:45 CEST 2013 Client_4: Reading received resources (399 ms): { a, b, c, d, e, f, g, h }. Lock: 22
Fri Oct 11 10:14:45 CEST 2013 Client_1: Reading received resources (230 ms): { a, b, c, d, f, g, h }. Lock: 23
Fri Oct 11 10:14:45 CEST 2013 Client_2: Reading received resources (544 ms): { a, b, d, e, f, g, h }. Lock: 20
Fri Oct 11 10:14:45 CEST 2013 Client_1: Reading requested resources: { a, b, c, d, f, g, h }
Fri Oct 11 10:14:45 CEST 2013 Client_1: Reading received resources (0 ms): { a, b, c, d, f, g, h }. Lock: 24
Fri Oct 11 10:14:45 CEST 2013 Client_3: Writing requested resources: { h }
Fri Oct 11 10:14:45 CEST 2013 Client_2: Reading requested resources: { a, b, d, e, f, g, h }
Fri Oct 11 10:14:45 CEST 2013 Client_0: Reading requested resources: { b, c, h }
Fri Oct 11 10:14:46 CEST 2013 Client_4: Reading requested resources: { a, b, c, d, e, f, g, h }
but here the program is frozen. I guess because of deadlock.
My question is: How can I fix this. I would really really apreciate if somebody could show me some working code example.