Cadence Inc Interview Question
Principal Software EngineersCountry: United States
Interview Type: In-Person
public class Application {
public static void main(String arg[]) {
ResourceSharing sharedResource = new ResourceSharing(10, 5);
Task tasks [] = new Task[5];
IntStream.range(0, tasks.length).forEach(i -> {
tasks[i] = new Task(++i, 2+i, sharedResource);
});
ExecutorService executorService = Executors.newCachedThreadPool();
Arrays.stream(tasks).forEach(executorService::execute);
}
}
public class Task implements Runnable {
private int threadNum;
private int requiredResources;
private ResourceSharing sharedResource;
public Task(int threadNum, int requiredResources, ResourceSharing sharedResource) {
super();
this.threadNum = threadNum;
this.requiredResources = requiredResources;
this.sharedResource = sharedResource;
}
@Override
public void run() {
try {
sharedResource.executeUsingResource(threadNum, requiredResources);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package phlilospher.sequence;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ResourceSharing {
final private int totalResources;
final private int totalConsumers;
final private Semaphore semaphore;
final private Lock lock;
final private Condition isNotInOrder;
private AtomicInteger currentOrder = new AtomicInteger(1);
public ResourceSharing(int totalResources, int totalConsumers) {
super();
this.totalResources = totalResources;
this.totalConsumers = totalConsumers;
this.semaphore = new Semaphore(totalResources);
this.lock = new ReentrantLock();
this.isNotInOrder = lock.newCondition();
}
public void executeUsingResource(int orderNo, int resources) throws InterruptedException {
if(resources > totalResources || orderNo > totalConsumers)
throw new IllegalArgumentException();
lock.lock();
try {
while(orderNo != currentOrder.get())
isNotInOrder.await();
semaphore.acquire(resources);
System.out.println("Thread : " + orderNo+ " running using resource : "+resources);
Thread.sleep(10);
System.out.println("Thread : " + orderNo+ " freeing resource : "+resources);
semaphore.release(resources);
currentOrder.getAndIncrement();
isNotInOrder.signalAll();
} finally {
lock.unlock();
}
}
}
lock in beginning of the method executeUsingResource will always allow only one thread to execute regardless the available resources
For example : thread t1 using 3 out of 10 resources will hold the lock
thread t2 using 4 out of 7 available resources will wait until t1 releases the lock.
{{
public class ResourceSharing {
final private int totalResources;
final private int totalConsumers;
final private Semaphore semaphore;
private AtomicInteger currentOrder = new AtomicInteger(1);
public ResourceSharing(int totalResources, int totalConsumers) {
super();
this.totalResources = totalResources;
this.totalConsumers = totalConsumers;
this.semaphore = new Semaphore(totalResources);
}
public void executeUsingResource(int orderNo, int resources) throws InterruptedException {
if(resources > totalResources || orderNo > totalConsumers)
throw new IllegalArgumentException();
while(orderNo != currentOrder.get()) {
//busy wait;
Thread.sleep(10);
}
semaphore.acquire(resources);
try {
currentOrder.getAndIncrement();
System.out.println("Thread : " + orderNo+ " running using resource : "+resources);
Thread.sleep(1000);
System.out.println("Thread : " + orderNo+ " freeing resource : "+resources);
} finally {
semaphore.release(resources);
}
}
}
}}
Output :
Thread : 1 running using resource : 3
Thread : 2 running using resource : 4
Thread : 1 freeing resource : 3
Thread : 3 running using resource : 5
Thread : 2 freeing resource : 4
Thread : 3 freeing resource : 5
Thread : 4 running using resource : 6
Thread : 4 freeing resource : 6
Thread : 5 running using resource : 7
Thread : 5 freeing resource : 7
public class ResourceSharing {
final private int totalResources;
final private int totalConsumers;
final private Semaphore semaphore;
final private Lock lock;
final private Condition isNotInOrder;
private AtomicInteger currentOrder = new AtomicInteger(1);
public ResourceSharing(int totalResources, int totalConsumers) {
super();
this.totalResources = totalResources;
this.totalConsumers = totalConsumers;
this.semaphore = new Semaphore(totalResources);
this.lock = new ReentrantLock();
this.isNotInOrder = lock.newCondition();
}
public void executeUsingResource(int orderNo, int resources) throws InterruptedException {
if(resources > totalResources || orderNo > totalConsumers)
throw new IllegalArgumentException();
lock.lock();
try {
while(orderNo != currentOrder.get())
isNotInOrder.await();
semaphore.acquire(resources);
System.out.println("Thread : " + orderNo+ " running using resource : "+resources);
Thread.sleep(10);
System.out.println("Thread : " + orderNo+ " freeing resource : "+resources);
semaphore.release(resources);
currentOrder.getAndIncrement();
isNotInOrder.signalAll();
} finally {
lock.unlock();
}
}
}
After the software development process, the software is optimized for real-time usage. This means that new versions of the software have to be made available to customers as soon as possible so that they can use it right away. After that, the software is deployed to a production environment to ensure that it is able to meet the expectations of the customer. During the production phase, the software is continuously improved and updated to make it more efficient https://mlsdev.com/services/custom-software-development. This phase of software development also includes improvements such as bug fixing, documentation improvement, documentation revamping and web site maintenance.
This is how I'd do it,
use counting semaphores for resources
thread will acquire required resources and process for a certain amount of time
release after the sleep
Note : variable time , t and sleep(t) have been used for fine tuning the start time of threads
and would not be required if its too much trouble
- PeyarTheriyaa November 11, 2018