how to achieve mutual exclusion using synchronized method in this application - java

i have run into a little problem in here. I am doing a concurrent program in Java. Problem is: There are 4 people (students) that are trying to access printer, to print 5 documents. But only one can print at the time (kind of obvious) 5 documents. When they finish they notify other that they done and other thread accesses the resource. i have a Main class, student class and Monitor (laser printer), Document class that holds info about the document like (number of pages, name user id etc)+ few interfaces for printer. I have managed to run successfully threads but they are not synchronized (mutual exclusion)
So the question is how do i achieve mutual exclusion ( that only one person can print at the time his number of docs)
Thank you for looking, time and hints :)
Main class
String S1Name = "bob";
String S2Name = "klara";
String S3Name = "John";
String S4Name = "Iga";
String T1Name = "Man";
String T2Name = "Woman";
final int NoOfDocs = 5;
ServicePrinter sp = new LaserPrinter();
ThreadGroup groupA = new ThreadGroup("Group A");
ThreadGroup groupB = new ThreadGroup("Group B");
Student student1 = new Student(sp,NoOfDocs,S1Name, groupA);
Student student2 = new Student(sp,NoOfDocs,S2Name, groupA);
Student student3 = new Student(sp,NoOfDocs,S3Name, groupA);
Student student4 = new Student(sp,NoOfDocs,S4Name, groupA);
TonerTechnician TT = new TonerTechnician(groupB);
PaperTechnician PT = new PaperTechnician(groupB);
/*
* Start Student Threads
*/
student1.start();
student2.start();
student3.start();
student4.start();
/*
* Start Technician threads
*/
TT.start();
PT.start();
Student Class
private final ServicePrinter serviceprinter;
private final int NoOfDocs;
private final String Name;
private final ThreadGroup threadgroup;
public Student(ServicePrinter serviceprinter, int NoOfDocs, String Name, ThreadGroup threadgroup)
{
this.serviceprinter = serviceprinter;
this.NoOfDocs = NoOfDocs;
this.Name = Name;
this.threadgroup = threadgroup;
}
#Override
public void run()
{
/*
* each students prints 5 documents (different name and length)
*/
final LaserPrinter lp = new LaserPrinter();
//sleep from 1 to 5 sec random time
final Random random = new Random();
char[] chars = "abcdefghijklmnopqrstuvwxyz".toCharArray();
StringBuilder sb = new StringBuilder();
/*
* Create random document name 10 characters long
*/
for (int i = 0; i < 10; i++)
{
char c = chars[random.nextInt(chars.length)];
sb.append(c);
}
String docName = sb.toString();
/*
* print 5 documents (random sleep time between printing)
*/
for(int i = 0; i < NoOfDocs; i++)
{
try
{
Document coursework = new Document(Name,docName,random.nextInt(90)+10);
lp.printDocument(coursework);
Thread.sleep(random.nextInt(1000)+4000);
}
catch (InterruptedException ex)
{
Logger.getLogger(Student.class.getName()).log(Level.SEVERE, null, ex);
}
}
System.out.println("User: " + Name+ " completed printing");
Monitor class
int tonerLevel = 500;
int paperLevel = 250;
private final String PrinterName = "HP";
private final String PrinterID = "LX-440";
private int CurrentPaperLevel;
private int CurrentTonerLevel;
private int NoOfDocsPrinted;
#Override
public synchronized void printDocument(Document document) {
System.out.println(document);
}

It seems that you're creating a local printer object in your run method instead of using the shared one you pass to the Student class. Try using the shared printer that you pass and see what you get. Also we need to see how you use printDocument in ServicePrinter. This is because you are using a ServicePrinter object in your Student class, and the implementation of printDocument in ServicePrinter may not be correct (that is if you actually have it implemented in the superclass)

Here is a simple mutex implementation but you should use java.util.concurrent package for synchronization
EDIT: Changed mutex to semaphore (it makes more sense)
A simple mutex implementaion:
public class Mutex {
private int semaphore;
public synchronized void aquire() throws InterruptedException {
if(semaphore < 0) {
wait();
}
semaphore--;
}
public synchronized void release() {
if(semaphore < 0) {
semaphore++;
notify();
}
}
}

Related

How can I assign a value to the threadArray variable in Task1 , Task2, Task3 class run() method?

I have to insert the elements using three threads by creating three classes, namely Task1,Task2 and Task3. The values to be inserted into the array are 0,1,2,....299.
Override the run method in the threads. Three integer i,j, and k representing the number of elements each thread should append inside the given array.
Thread one should append 0 to i-1 inside the array,thread two should append i to i+j-1 inside the array,and the third thread should append i+j to 299 inide the array.
Threads one and two must run simultaneously, and the values of the threads one and two must be inserted inside the indices of the array from 0 to i+j-1 randomly.The third thread should start only after the first two threads have been executed completely.
In these code three task are given.
first task and second task start executing the thread at the same time and after completion of first two task then only third task start. If these situation getting correct then test() method return true.
public static final int[] threadArray = new int[300]; how I add random number into these array using Task1 Task2 and Task3 class.
Input :
80
130
90
Output :
True
import java.util.Scanner;
class Task1 extends Thread
{
static int a = 0;
static int beg = 0;
public void run()
{
for(int i=a;i<=beg;i++)
{
Solution.threadArray[i] = i;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class Task2 extends Thread
{
static int a = 0;
static int beg = 0;
#Override
public void run()
{
// TODO Auto-generated method stub
for(int i=a;i<=beg;i++)
{
Solution.threadArray[i] = i;
}
}
}
class Task3 extends Thread
{
static int a = 0;
static int beg = 0;
public void run()
{
// TODO Auto-generated method stub
for(int i=a;i<=beg;i++)
{
Solution.threadArray[i] = i;
}
}
}
public class Solution
{
public static final int[] threadArray = new int[300];
public static volatile String i = 0+"";
public boolean test() throws InterruptedException
{
Task1 task1 = new Task1();
Task2 task2 = new Task2();
Task3 task3 = new Task3();
Thread task2Thread = new Thread(task2);
Thread task3Thread = new Thread(task3);
task1.start();
task2Thread.start();
task1.join();
task2Thread.join();
task3Thread.start();
int first = Task1.a+Task2.a;
int containsSecondThread = Task1.a;
String oneAndTwo = "";
String sizeOfTask1 = "";
for(int i=0;i<first;i++)
{
oneAndTwo += threadArray[i]+" ";
}
for(int i=0;i<containsSecondThread;i++)
{
sizeOfTask1 += threadArray[i]+" ";
}
int begOfTask3 = Task3.beg;
String checkingString = "";
for(int i=begOfTask3;i<threadArray.length;i++)
{
checkingString += i + " ";
}
String task3String = "";
for(int j = begOfTask3;j<threadArray.length;j++)
{
task3String += threadArray[j]+" ";
}
if((!oneAndTwo.contains(begOfTask3+"") && sizeOfTask1.contains(Task2.beg+"")) || task3String.equals(checkingString))
{
return true;
}
return false;
}
public static void main(String[] args) throws InterruptedException
{
Scanner sc= new Scanner(System.in);
Solution solution = new Solution();
int one = sc.nextInt();
Task1.a = one;
Task1.beg = 0;
int two = sc.nextInt();
Task2.a = two;
Task2.beg = one;
int three = sc.nextInt();
Task3.a = three;
Task3.beg = one+two;
System.out.print(solution.test());
}
}
First, some observations regarding your code: Instead of using static variables in the classes (i.e., Task1, Task2, and Task3) that extend the class Thread (to understand why have a look at Why are static variables considered evil?):
static int a = 0;
static int beg = 0;
use non-static final fields, and initialize them via the constructor:
class Task1 extends Thread
{
private final int begin;
private final int end;
Task1(int begin, int end){
this.begin = begin;
this.end = end;
}
public void run(){
for(int i=begin; i<= end; i++)
....
}
}
adapt the main method accordingly:
public static void main(String[] args){
...
Task1 task1 = new Task1(begin, end);
}
and then pass the tasks-related objects as parameters of to the test method:
public boolean test(Task1 task1, Task2 task2, Task3 task3){
...
}
For the concatenation of the strings use StringBuilder:
StringBuilder oneAndTwo = new StringBuilder();
for(int i=0;i<first;i++)
{
oneAndTwo.append(threadArray[i]).append(" ");
}
This looks wrong:
Task1.a = one;
Task1.beg = 0;
by looking at the loop of the run method from Task1, this means that, if Task1.a is not a negative number, then Task1 will not do any work.
To use the threads to generate the random values of the array:
int[] threadArray = new int[300];
you can start by extracting a method to generate those random values, based on formula:
r.nextInt(high-low) + low;
this formula generates a random value between low and high.
Adapt the tasks, accordingly:
class Task1 extends Thread
{
private final Random random_values = new Random();
private final int low;
private final int high;
...
public int generate_random(){
return r.nextInt(high-low) + low;
}
public void run()
{
for(....)
{
Solution.threadArray[i] = generate_random();
...
}
}
}
Make sure to pass to the threads the information about the range of the random values to be generated (i.e., the low and high parameters), and the reference to the array that will be filled up with those random values (i.e., array int[] threadArray) . Also make sure that you split the iterations int[] threadArray among the threads. Therefore, each thread should generate a chunk of the random values. An example of such distribution would be:
Thread 1 : 0 to 100;
Thread 2 : 100 to 200;
Thread 3 : 200 to 300;
You can make this more robust and divide the array length by the number to threads and assign the work among threads, accordingly.
I could have provided you with the entire solution, but I feel that is better instead if I give you the pointers so that you can do it in your own.
EDIT: Based on the new edit of your question:
You just need to adapt the Task classes as follows:
class Task1 extends Thread {
static int a = 0;
static int beg = 0;
public void run(){
for(int i=beg;i < a;i++)
Solution.threadArray[i] = i;
}
}
class Task2 extends Thread {
static int a = 0;
static int beg = 0;
public void run(){
for(int i=beg; i< beg + a;i++)
Solution.threadArray[i] = i;
}
}
class Task3 extends Thread{
static int a = 0;
static int beg = 0;
public void run(){
for(int i=beg;i< a + beg;i++)
Solution.threadArray[i] = i;
}
}
Thread1 and Thread2 are supposed to access Common Resource in threadArray[0... Task1.a+Task2+a]. So we have to make use of static volatile variable i declared in Solution Class.
class Task1 extends Thread
{
static int a=0,beg=0;
public void run()
{
int k=Task1.beg;
int i1=0;
while(i1<Task1.a)
{
Solution.threadArray[Integer.parseInt(Solution.i)]=k++;
int a1=Integer.parseInt(Solution.i);
a1++;i1++;
Solution.i=a1+"";
try{
Thread.sleep(1);
}
catch(InterruptedException e){}
}
}
}
class Task2 extends Thread
{
static int a=0,beg=0;
public void run()
{
int y=0;
int k=Task2.beg;
while(y<Task2.a)
{
Solution.threadArray[Integer.parseInt(Solution.i)]=k++;
int a1=Integer.parseInt(Solution.i);
a1++;y++;
Solution.i=a1+"";
try{
Thread.sleep(1);
}
catch(InterruptedException e){}
}
}
}
Thread3 work independently after First 2 threads complete.
class Task3 extends Thread
{
static int beg=0,a=0;
public void run()
{
for(int i=Task3.beg;i<Task3.beg+Task3.a;i++)
{
Solution.threadArray[i]=i;
}
}
}

How to synchronise threads and preserve their execution order with CyclingBarrier?

I want to write a multithread app that prints characters from Strings one by one and after first "round" it would preserve order for the other rounds. It should work somehting like this:
For Strings:
private String[] strings = {"aaaa", "bb", "ccccccccccccc", "dddddd"};
It would print:
abcd abcd acd acd cd cd c c c c c c c
or maybe
dbac dbac dac dac dc dc c c c c c c c
depending on which proccess started first in the very first round
My solution so far looks like this
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Printer {
private CyclicBarrier cyclicBarrier;
private final static String one = "aaa";
private final static String two = "bbbb";
private final static String three = "c";
private final static String four = "dddddd";
public static void main(String[] args) {
Printer printer = new Printer();
printer.runSimulation(4);
}
private void runSimulation(int numberOfStrings) {
cyclicBarrier = new CyclicBarrier(numberOfStrings, new AggregatorThread());
Thread thread = new Thread(new PrintingThread(padSpaces(one, 10)));
Thread thread1 = new Thread(new PrintingThread(padSpaces(two, 10)));
Thread thread3 = new Thread(new PrintingThread(padSpaces(three, 10)));
Thread thread4 = new Thread(new PrintingThread(padSpaces(four, 10)));
thread.start();
thread1.start();
thread3.start();
thread4.start();
}
class AggregatorThread implements Runnable{
#Override
public void run() {
System.out.print(" ");
}
}
class PrintingThread implements Runnable{
private String toPrint;
private int iterator;
public PrintingThread(String toPrint) {
this.toPrint = toPrint;
this.iterator = 0;
}
#Override
public void run() {
while(iterator < toPrint.length()) {
System.out.print(toPrint.charAt(iterator));
iterator++;
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
private String padSpaces(String inputString, int length) {
if (inputString.length() >= length) {
return inputString;
}
StringBuilder sb = new StringBuilder();
while (sb.length() < length - inputString.length()) {
sb.append(' ');
}
StringBuilder sb1 = new StringBuilder(inputString);
sb1.append(sb);
return sb1.toString();
}
}
But it doesn't preserve the order of letters written to the console and also i fill the Strings to the some hardcoded value right now, but i would want to make it work properly without equal strings.
Any suggestions on this?
Since you're asking for a solution with CyclicBarrier, here's a way you could do this with one... It definitely wouldn't be my first thought for how to solve the issue though (assuming the issue isn't 'do this with a CyclicBarrier'...).
Create a CyclicBarrier of length 4.
Assign each Thread a number (0 to 3) when it starts (using an AtomicInteger or otherwise).
Have each Thread do something like:
while (barrier.getNumberWaiting() != this.threadNumber) {
}
// Do your adding to the StringBuilder here...
barrier.await();
I.e. each Thread spins until the number of waiting parties is equal to that Thread's number.
Whichever is assigned 0 will always go through first, while all the others are stuck spinning. Once that Thread has done its StringBuilder thing, it will then await, which in turn frees the Thread assigned 1 to go through. The order will stay consistent after the number assignments.
To get the unique id per process, a simple AtomicInteger can be used.
private final AtomicInteger idCounter = new AtomicInteger();
private final CyclicBarrier barrier = new CyclicBarrier(4);
private final AtomicInteger doneCounter = new AtomicInteger();
public Runnable createRunnable() {
return () -> {
final int threadId = this.idCounter.getAndIncrement();
boolean threadDone = false;
boolean moreCharacters = true;
while (true) {
while (this.barrier.getNumberWaiting() != threadId) {
}
// Add to StringBuilder here...
// Set the 'moreCharacters' flag as false once this thread
// has handled its String.
// They will still need to spin though, to make sure the
// parties waiting keep adding up as appropriate.
if (!moreCharacters && !threadDone) {
// 'threadDone' used so that each thread only
// increments the 'doneCounter' once.
this.doneCounter.incrementAndGet();
threadDone = true;
}
barrier.await();
if (this.doneCounter.get() == 4) {
// Exit out of the loop once all Threads are done.
break;
}
}
};
}

How to understand which thread is making a new variable during debugging?

I'm studying Java and I'm working on a very simple code that start 3 threads.
Is composed by 3 classes
TxColor change the color to the text printed in console from the threads
ThNew build and run the threads
ThRandy start the threads (main function)
TxColor
/*
to color the output text
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
class TxColor {
public static final String ANSI_RESET = "\u001B[0m";
public static final String ANSI_BLACK = "\u001B[30m";
public static final String ANSI_RED = "\u001B[31m";
public static final String ANSI_GREEN = "\u001B[32m";
public static final String ANSI_BLUE = "\u001B[34m";
public static final String ANSI_PURPLE = "\u001B[35m";
public static final String ANSI_CYAN = "\u001B[36m";
private static Random r = new Random();
private static String oldpick = "null";
private static ArrayList<String> l = new ArrayList<>(Arrays.asList(ANSI_RESET,ANSI_BLACK,ANSI_RED,ANSI_GREEN,ANSI_BLUE,ANSI_PURPLE,ANSI_CYAN));
static ArrayList<String> getCList(){
return l;
}
// choose a random color thread
static String colPick(){
String col = "null";
int count = 0;
do{
count++;
int n = r.nextInt(l.size());
col = getCList().get(n);
}while (col==oldpick && count<10);
count = 0;
oldpick=col;
return col;
}
}
ThNew
import java.util.Random;
public class ThNew extends Thread {
private String name = "standard";
ThNew(String name){
this.name = name;
}
#Override
public void run(){
try{
sleep(new Random().nextInt(1000));
}catch (Exception e){
e.printStackTrace();
}
System.out.println(TxColor.colPick()+"Thread " + name + " started");
}
}
ThRandy
import java.util.Random;
public class ThRandy {
public static void main(String[] args) {
Random r = new Random();
ThNew th1 = new ThNew("Mario");
ThNew th2 = new ThNew("Giorgio");
ThNew th3 = new ThNew("Andrea");
th1.start();
th2.start();
th3.start();
}
}
In the module colPick() I use the variable count to be sure 100% the code end exiting the loop in case is not able to pick a random color different from the previous one.
If you notice the count variable is not static, so every thread has is own count variable.
I didn't use synchronize to reproduce the issue I will describe you.
When I debug using Intellij https://www.jetbrains.com/idea/ I have this screen
I don't know if is common also in Eclipse or any other IDE, but as you can see in the picture I cannot recognize the int count variable of one thread from another. I only notice to have more than one count because the debug jump forward and back again in the code due to the presence of multiple thread.
There is a way to understand which thread is creating that specific count variable?
Thank you very much for help.
I found the solution and I wish to contribute with my help.
You just open the curtain menu as shown in the picture and you can see every thread with their own variables
An easier approach to this problem is to rearrange the list: pick a random element in the list, swap it with the last element, and always return the last element in the list:
static int e = l.size(); // added
static synchronized String colPick(){
int n = r.nextInt(e);
int last = l.size() - 1;
Collections.swap(l, n, last);
e = last;
return l.get(last);
}
The way this works is a bit subtle.
Initially, e, the range of random numbers you can pick, is the size of the list, so this allows any colour to be picked first time.
The picked element is then swapped with the element at the end of the list
e is then updated to be one less than the size of the list: this means that, on the next iteration, the last element of the list can't be picked. As such, it is guaranteed that the same element can't be picked twice in a row (unless there are two equal elements).
Note that this has to be synchronized for two reasons:
You aren't using a thread-safe random class, such as ThreadSafeRandom.
The swapping and reading of the last item, and the update to e, has to be done atomically.

Static Method Java confusion

Room Class:
public abstract class Room {
public abstract int cost();
public static Room mostExpensive = null;
public static int highestCost = 0;
public static Room mostExpensive() {
return mostExpensive;
}
}
Lab Class:
public class Lab extends Room{
public final int LAB_CHAIR_PRICE = 50;
int labChairs;
int computers;
private final int COMPUTER_COST = 1000;
public Lab(int labChairs, int computers) {
this.labChairs = labChairs;
this.computers = computers;
if (this.cost() > highestCost) {
mostExpensive = this;
highestCost = this.cost();
}
}
public int cost() {
return ((LAB_CHAIR_PRICE * labChairs) + (COMPUTER_COST * computers));
}
}
LectureHall Class:
public class LectureHall extends Room {
private final int LECTURE_CHAIR_PRICE = 100;
int lectureChairs;
boolean isData;
private final int DATA_PROJECTOR_COST = 5000;
int dataProjector;
public LectureHall(int lectureChairs, boolean isData) {
this.lectureChairs = lectureChairs;
if (this.isData = isData) {
this.dataProjector = 1;
if (this.cost() > highestCost) {
mostExpensive = this;
highestCost = this.cost();
}
}
}
public int cost(){
return ((LECTURE_CHAIR_PRICE * lectureChairs) + (DATA_PROJECTOR_COST * dataProjector));
}
}
Test Class
public class Test {
public static void main(String[] args) {
// An array of rooms for a proposed new building
Room rooms[] = new Room[4];
// small lecture hall with a data projector
rooms[0] = new LectureHall(40, true);
// large lecture hall seating 500, with no data projector
rooms[1] = new LectureHall(500, false);
// lab with seats for 50 and a computer for every two
rooms[2] = new Lab(50,25);
// smaller lab with seats for 10 and a computer for each
rooms[3] = new Lab(10,10);
int totalCost = 0;
for (int i = 0; i < rooms.length; i++) {
System.out.println("room " + i + " costs $" + rooms[i].cost());
totalCost += rooms[i].cost();
}
System.out.println("total cost: $" + totalCost);
Room r = Room.mostExpensive(); // the most expensive room created
// by the program
System.out.println("the most expensive room costs $" + r.cost());
}
}
So i'm having a little trouble with the mostExpensive method(). Its a static method and I declared it in the room class, but its used by the other methods. Its supposed to find the most expensive Room. However, it doesn't find the most expensive one, and it tells me that 27500 is the most expensive (which is not). Also I had a question about the Room class. In the constructor i set mostExpensive = this. Does that work? I'm a little confused as to how all of this works, and how I can do it correctly.
In this constructor, the "mostExpensive" is only modified if there is a projector.
public LectureHall(int lectureChairs, boolean isData){
this.lectureChairs = lectureChairs;
if (this.isData = isData){
this.dataProjector = 1;
if (this.cost() > highestCost){
mostExpensive = this;
highestCost = this.cost();
}
}
}
Fix:
public LectureHall(int lectureChairs, boolean isData){
this.lectureChairs = lectureChairs;
if (this.isData = isData){
this.dataProjector = 1;
}
if (this.cost() > highestCost){
mostExpensive = this;
highestCost = this.cost();
}
}
But one should not compute overall state in the constructor of a single object. This is poor design. Keep track of Rooms in some class - either Room or something new, e.g Building. Then compute the "most expensive" from whatever you have in Room. Imagine: what happens if a projector is removed? Or added in another existing Lecture Room? The possibilities of making errors are overwhelming.

Access string from outside a thread

I am new to java world and and I've been trying to find answer to this question and couldn't. So can someone explain how can I use already initialized String from outside a thread. Here is the code the string I want to use is "name" but if I make "name" final I can't set value to it.
public class Users {
public static void GenerateNames() {
String name = "";
String str;
for (int i = 0; i <= 2; i++)
name = name + RandNames.GenerateRandomChar();
str = name;
Hashtable ht = new Hashtable();
if (ht.get(str) == null)
{
ht.put(str, name);
}
else {
}
Runnable r = new Runnable() {
public void run() {
int Anketa = (int) (1 + Math.random() * 6);
Hashtable voting = new Hashtable();
if (voting.get(name) == null)
{
}
}
};
new Thread(r).start();
}
}
Also is there a problem that I left "else" empty. I just need it to do nothing.
Just move the code that generates name into a separate method:
public static String GenerateRandomName() {
StringBuilder name = new StringBuilder();
for (int i = 0; i <= 2; i++) {
name.append(RandNames.GenerateRandomChar());
}
return name.toString();
}
The you'll be able to make name final:
public static void GenerateNames() {
final String name = GenerateRandomName();
...
}
Also is there a problem that I left "else" empty. I just need it to do nothing.
Just omit it altogether:
if (ht.get(str) == null)
{
ht.put(str, name);
}
One way to solve this type of problem is to use a second local variable:
public static void GenerateNames() {
String workName = ""; // you can probably think of a better variable name
for (int i = 0; i <= 2; i++)
workName = workName + RandNames.GenerateRandomChar();
final String name = workName;
and now you can use name in your anonymous inner class. (This is a pattern I use fairly often.)
In order to use name variable inside the run method you can declare this variable as a member of the Users class and mark it as static because it is used in static scope.
public class Users {
private static String name = "";
public static void GenerateNames() {
// your code
Runnable r = new Runnable() {
public void run() {
int Anketa = (int) (1 + Math.random() * 6);
Hashtable voting = new Hashtable();
if (voting.get(name) == null) {
}
}
};
new Thread(r).start();
}
}

Categories