So I have been trying to sort this out for a couple of hours now and I'm sure its something really simple or just a simple mistake i am missing but i have a three class program, control, account and MyThreads.
Im trying to have multipule threads(cards) modify the single account, i'm trying to use a monitor so only one thread can make changes at a time, this is not what i have archived I have somehow just allowed the one thread to access the account class and no others, they seem to just disappear, i assume they are just all on wait but refuse to wake up... any help before i implode?
account code:
class account{
private static int value = 0;
private static int cards = 0;
private static int count = 0;
private static int lock = 0;
public void setValue(int temp){
value = temp;
}
public int getValue(){
// while(lock == 1){
// try{
// wait();
// }catch (InterruptedException e){
// }
// }
return value;
}
synchronized public void withdraw(int temp, String tempID){
while(lock == 1){
try{
wait();
}catch (InterruptedException e){}
}
lock=1;
value= value - temp;
count++;
System.out.println(count + "(" + tempID +")"+" "+temp+" - "+value);
lock = 0;
this.notifyAll();
}
synchronized public void deposit(int temp, String tempID){
while(lock == 1){
try{
wait();
}catch (InterruptedException e){}
}
lock=1;
value= value + temp;
count++;
System.out.println(count + "(" + tempID +")"+" - "+temp+" "+value);
lock = 0;
this.notifyAll();
}
public void setCards(int temp){
cards = temp;
}
public int getCards(){
return cards;
}
public int getCount(){
return count;
}
}
control code:
class control{
public static void main(String [] args){
account acc = new account();
acc.setValue(1000);
acc.setCards(5);
// if(args.length > 0){
// try{
// int tempCards = Integer.parseInt(args[0]);
//
// }catch (NumberFormatException e) {
// System.err.println("Number of Cards : " + args[0] + " must be an integer.");
// System.exit(1);
// }
// try{
// int tempVal = 0;
// tempVal = Integer.parseInt(args[1]);
// acc.setValue(tempVal);
// }catch (NumberFormatException e) {
// System.err.println("Account Value : " + args[1] + " must be an integer.");
// System.exit(1);
// }
// }else{
// System.err.println("No values found, please start program with the number of Cards and Bank Account Value, both in integer format");
// System.exit(1);
// }
System.out.println("Transaction Withdrawal Deposit Balance");
System.out.println(" " + acc.getValue());
for(int i=0; i<=((acc.getCards())-1); i++){
new MyThreads(Integer.toString(i+1));
}
}
}
MyThreads code:
class MyThreads implements Runnable{
private String ID;
private Thread t;
account acc = new account();
MyThreads(String tempID){
ID = tempID;
t = new Thread(this, ID);
t.start();
}
public void run(){
try{
for (int i = 0; i < 20; i++){
if(Math.random()>0.5){
int tempW = 0;
tempW = ((int)(Math.random()*100));
acc.withdraw(tempW, this.ID);
//System.out.println(acc.getCount() + "(" + this.ID +")"+" "+tempW+" -"+acc.getValue());
}else{
int tempD = 0;
tempD = ((int)(Math.random()*100));
acc.deposit(tempD, this.ID);
//System.out.println(acc.getCount() + "(" + this.ID +")"+" "+" - "+tempD+" "+acc.getValue());
}
t.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Thread " + ID + " interrupted.");
}
System.out.println("Thread " + ID + " exiting.");
}
}
I know its a mess, forgive me im lazy.
Have a look at the definition of a Monitor in Java. In your code, you use the keyword synchronized for two methods, which are the same as:
public void XX(){
lock.lock(); // lock is a private variable
try {
// code here
} finally {
lock.unlock();
}
}
In short, It is a shorthand for explicit locking and will prevent multiple threads to access the methods concurrently.
So, just remove the lock part (i.e. the while(lock==1) block) inside your synchronized methods and it will work. Also, if in other codes you need a real lock, use the Lock class, not an integer.
For more information, there are a lot of good introduction to multithreading on the web, for example this one.
Your question, and thus answer, is a wonderful mixture of static synchronized and wait-notify that's neve being called. Why use static? sounds like a magic word? skip static and make life easier.
Also note that a wait-notify is related to a specific object; if wait-notify are related to different objects they will not communicate. Have a single object that they all synchronize around.
Related
I tried to print odd number in one thread and even number in another. I tried creating two thread and printing it in run method.
public class OddEven
{
private final int MAX = 10;
private static int counter = 0;
private volatile boolean isOdd = true;
public synchronized void printEven(int counter)
{
try {
if (!isOdd) {
System.out.println(Thread.currentThread().getName() + " " + counter);
counter++;
isOdd = true;
}
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printOdd(int counter)
{
if (isOdd) {
counter++;
System.out.println(Thread.currentThread().getName() + " " + counter);
isOdd = false;
}
notifyAll();
}
public static void main(String[] args) {
OddEven oddEven = new OddEven();
Thread th1 = new Thread() {
public void run() {
while (OddEven.counter < oddEven.MAX) {
oddEven.printEven(OddEven.counter);
}
}
};
th1.setName("even -");
th1.start();
Thread th2 = new Thread() {
public void run() {
while (OddEven.counter < oddEven.MAX) {
oddEven.printOdd(OddEven.counter);
}
}
};
th2.setName("odd -");
th2.start();
}
}
But it is printing it like below infinitely.
even - 0
odd - 1
even - 0
odd - 1
even - 0
odd - 1
To read: Is Java "pass-by-reference" or "pass-by-value"?
You pass in a primitive. counter++; makes sense only within the method and has no impact on the outer world. count refers to the method param, not to the field this.count.
There is no proper synchronisation placed upon the condition OddEven.counter < oddEven.MAX, so different things may happen.
My advice would be to remove isOdd and do a check on the spot. For instance,
public synchronized void printEven() {
if (counter % 2 != 0) {
System.out.println(Thread.currentThread().getName() + " " + ++counter);
}
}
The line oddEven.printEven(OddEven.counter) passes an integer by value to the printEven method which does not change the value of OddEven.counter when it does counter++ as also pointed in other answers here.
To get the desired output, one option is to remove the passed parameter to both printEven and printOdd methods. And there are many other ways to achieve what you are trying to do here.
And there is also a mistake in the printEven method. counter++; needs to be before the print statement.
This will give you the desired output.
In the problem I am trying to solve, each thread has to read the whole file, (maybe each thread will deliver its content to another task or any other purpose). After reading it, the thread should sleep a bit then try to read the file again, and only a given number(n) of threads should read the file. My attempt to solve this dealing with controling the amount of threads working is in the code below :
import java.util.*;
class Reader implements Runnable{
Thread t;
Controler c;
public Reader(Controler c){
t = new Thread(this);
this.c = c;
t.start();
}
public void run(){
Random ran = new Random();
int napTime;
while(true){
try{
w.intentarLeerArchivo(t);
//Specification says that each reader
//should wait a bit before trying to
//read the file again
napTime = ran.nextInt(1000);
t.sleep(napTime);
}catch(InterruptedException e){
System.out.println("InterruptedException");
}
}
}
}
class Controler{
Random ran;
LinkedList <Reader> readers;
int n;
int count;
public Controler(int n){
readers = new LinkedList <Reader>();
this.n = n;
count = 0;
ran = new Random();
}
public synchronized void getPermission(){
try{
while(count >= n){
wait();
}
notify();
}catch(InterruptedException e){
System.out.println("InterruptedException");
}
}
public synchronized void increaseCount(){
count++;
}
public synchronized void decreaseCount(){
count--;
System.out.println("There are " + count + " threads reading");
}
public void intentarLeerArchivo(Thread t){
int readTime = 1000;
try{
getPermission();
System.out.println("Thread " + t.getId() +" empezó a leer");
increaseCount();
t.sleep(readTime);
System.out.println("Thread " + t.getId() +" is reading");
System.out.println("Thread " + t.getId() + " finished reading");
decreaseCount();
} catch(InterruptedException e){
System.out.println("InterruptedException");
}
}
}
class Initializer{
int numReaders;
int maxReaders;
public Initializer(int numReaders, int maxReaders){
this.numReaders = numReaders;
this.maxReaders = maxReaders;
}
public void init(){
Controler c = new Controler(maxReaders);
for(int i = 0; i < numReaders; i++){
new Reader(c);
}
}
}
public class FileShare{
public static void main(String [] args){
Initializer c = new Initializer(100, 50);
c.init();
}
}
There are a few lines I wrote in order to debug. They print the state of each thread and the number of threads that are reading whenever one of them ends reading. But when I run the program, it turns out that suddenly there are more Threads reading the file than the ones there were supposed to be doing so. I guess it has something to do with my synchronization manipulation. What am I doing wrong?
When a thread is in the
while(...){wait()}
section of your implementation, it wait until someone notify it to go on. Right now, when you finish waiting, you notify right away.
Think about it, if once I get in I notify someone to come, he will not wait until I'm done before coming in. You want to use notify when you leave the file.
i'm trying to create a void method that will read csv file and count the reputaion number of state such that how many times TX,how many times Oh and how many times of Dc. the out should be-TX=4; Oh=2;DC=2. but my out put is "For input string: "F" "- and i really couldn't get where is the problem.can someone help me?
"Crimerate.csv"
State county Rate
Tx,DALLAs,39
TX,Aderson,10
Oh,Archer,20
DC,DC,50
Tx,Houston,31
TX,Claude,13
Oh,Bexar,10
DC,SE,40
public static void countnumber()
{
try{
List<String>number=Files.readAllLines(Paths.get("Crimerate.csv"));
double sum=0,num=0;
for (String line:number){
if(num==0){
++num;
continue;
}
line=line.replace("\"","");
String []result=line.split(",");
double close = Double.parseDouble(result[6]);
String numberAsString = Double.toString(close);
if(numberAsString.equals("Tx"))
{
sum++;
System.out.println("number of Tx =" + sum);
}
else if(numberAsString.equals("Oh"))
{
sum++;
System.out.println("number of Oh =" + sum);
}
else if(numberAsString.equals("Dc"))
{
sum++;
System.out.println("number of Dc =" + sum);
}
}
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void main (String args[])
{
countnumber();
}
While the previously suggested answers will address the specific question of why there was only a single response (a result of having only a single sum variable), they have two issues.
They are not accounting for the fact that in the example data, Texas is shown both as "Tx" and "TX". Thus, the current other answers will not give the correct result of 4 for Texas (they will only show 2).
The approaches assume that the full data set was shown. If other states are present, then the code would need to be continually expanded to support the new states.
This solution handles both situations.
public static void main(String[] args)
{
Map<String, Integer> countByState = new HashMap<>();
List<String> number;
try {
number = Files.readAllLines(Paths.get("f:/tmp/Crimerate.csv"));
int cntr = 0;
for (String line : number) {
// skip first line
if (cntr++ == 0) {
continue;
}
String []result=line.split(",");
// should add error checking
String state = result[0].toUpperCase();
Integer cnt = countByState.get(state);
if (cnt == null) {
cnt = new Integer(0);
}
countByState.put(state, ++cnt);
}
System.out.println(countByState);
}
catch (IOException e) {
e.printStackTrace();
}
}
Sample Results based upon the data presented in the question (there is only one DC in that data):
{TX=4, OH=2, DC=1}
int txCount = 0;
int ohCount = 0;
int dcCount = 0; //create this variables inside the class(instance variables)
if(numberAsString.equals("Tx"))
{
++txCount;
System.out.println("number of Tx =" + txCount);
}
else if(numberAsString.equals("Oh"))
{
++ohCount;
System.out.println("number of Oh =" + ohCount);
}
else if(numberAsString.equals("Dc"))
{
++dcCount;
System.out.println("number of Dc =" + dcCount);
} //its better if u use equalsIgnoreCase on if Statements
you were referring to same sum variable on each if loops, i have fixed that .
i assume that the code you have written on reading the file is correct.
You just need different sum variables for each sum. And print the results after the loop.
try{
List<String>number=Files.readAllLines(Paths.get("Crimerate.csv"));
double sumTx=0,sumOh=0,sumDc=0,num=0;
for (String line:number){
if(num==0){
++num;
continue;
}
line=line.replace("\"","");
String []result=line.split(",");
double close = Double.parseDouble(result[6]);
String numberAsString = Double.toString(close);
if(numberAsString.equals("Tx")) {
sumTx++;
} else if(numberAsString.equals("Oh")){
sumOh++;
} else if(numberAsString.equals("Dc")){
sumDc++;
}
}
System.out.println("number of Tx =" + sumTx);
System.out.println("number of Oh =" + sumOh);
System.out.println("number of Dc =" + sumDc);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
I am trying to make program which simulates a waitingline and lift, and individual skiers.
Now my output is fine and as expected until the skiers hit the top of the lift then begin to ski, which is when the threads begin.
My problem is, once a skier is finished he should then pend himself back into the waiting line, but alot of the skiers go missing, and never return to the line.
Any ideas?
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ThreadsAssignment {
// Declare and initalise queues and arrays
public static BlockingQueue<String> liftQueue = new LinkedBlockingQueue<String>(11);
public static BlockingQueue<String> waitQueue = new LinkedBlockingQueue<String>();
public static String toLift;
public static String toWait;
public static String liftFront = "EMPTY";
public static String waitFront;
public static int populatedLift = 0;
public static int pauseLift;
public static int slopeTime;
public static String toPend;
public static int queueSize;
public static void main(String[] args) throws Exception{
// fill both queues list for startup
for(int i = 0; i < 30; i++){
waitQueue.add(Integer.toString(i));
}
for(int j = 0; j < 10; j++){
liftQueue.add("EMPTY");
}
// loop the simulation
while(true){
System.out.println("In Queue " + "(" + waitQueue.size() + "): " + waitQueue);
System.out.println("On Lift " + "(" + populatedLift + "): " + liftQueue + "\n");
// Stop lift for 1 second
try{
Thread.sleep(1000);}
catch (InterruptedException ex) {}
// test if the lift stops
if ((Math.random() * 100) >= 95) {
Random rand = new Random();
pauseLift = rand.nextInt(8001);
System.out.println("Lift paused for " + pauseLift + " milliseconds");
try{Thread.sleep(pauseLift);}
catch (InterruptedException ex){}}
else{}
// get the head of the waiting line then add it to lift, check if any skier is waiting.
liftFront = liftQueue.peek();
if (waitQueue.size() == 0){
liftQueue.add("EMPTY");
}
else{
toLift = waitQueue.take();
liftQueue.add(toLift);
populatedLift++;
}
// if the front of the liftQueue is occupied, call a new skier thread
if (liftFront.equals("EMPTY")){
liftQueue.poll();}
else{
liftQueue.poll();
populatedLift--;
skier s = new skier(liftFront, waitQueue);
new Thread(s).start();
}
}
}
// skier thread
public static class skier extends Thread {
static String name;
static BlockingQueue<String> theQueue;
// Constructor for the thread
public skier(String name, BlockingQueue<String> theQueue){
skier.name = name;
skier.theQueue = theQueue;
}
// run method that makes random skiing time then pends the skier back into the queue
#Override public void run() {
toPend = skier.name;
Random speed = new Random();
slopeTime = speed.nextInt(10001) + 2000;
try {Thread.sleep(slopeTime);}
catch (InterruptedException ex){}
currentThread.
if (waitQueue.contains(toPend)){}
else {try {
waitQueue.put(toPend);
} catch (InterruptedException e){}
System.out.println(toPend + "has been pended");}
}
}
}
Following code may cause skiers to become missing:
static String name;
static BlockingQueue<String> theQueue;
static means that all instances of skier will share last submitted name. You must make all skiers keep their names to themselves:
final String name;
final BlockingQueue<String> theQueue; // this may be left `static` since there's only one instance, but this would be unclean code.
// Or, as an option, let `skier` instances re-use outer class `queue`.
Btw, Java has convention of starting class names with upper-case letter, so it should be Skier as well.
And you don't need EMPTY constant, just call queue.isEmpty()
I have just started studying multithreading and I wrote a code to understand that. Unfortunately I'm stuck with a deadlock and can't figure out how to solve that.
Simple Producer Consumer Problem.
Teacher generates a number, puts it on table, notifies the students, students check if the number is what they need, they pick it up, notify the teacher, and teacher again generates a number.
Problem : The code stops after the teacher produces a random number and notifies the students
Output is something like this:
Created S1
Created S2
Created S3
Created Teacher
waiting S1
waiting S3
waiting S2
3
Notified
Code :
public class Student extends Thread{
String name;
int held;
int needed;
Table tab;
Student(String name, int held, Table tab){
this.name = name;
this.held = held;
needed = 7 - held;
this.tab = tab;
System.out.println("Created " + name);
}
public void run(){
while(true){
synchronized(this){
while(tab.contains() == 0){
try{
System.out.println("waiting " + name);
wait();
System.out.println("wait over in loop");
}
catch(InterruptedException e){
System.out.println("Err!");
}
}
System.out.println("wait over" + name);
if(tab.contains() == needed){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
tab.remove();
System.out.println("Drawing made by " + name);
notifyAll();
}
}
}
}
}
public class Teacher extends Thread{
String name;
Table tab;
public Teacher(String name, Table tab){
this.name = name;
this.tab = tab;
System.out.println("Created " + name);
}
public void run(){
synchronized(this){
while(true){
while(tab.contains()>0){
try{
wait();
}
catch(InterruptedException e){
System.out.println("Boo");
}
}
int value = 0;
while ((value != 3) && (value != 5) && (value != 6)){
value = (int)(1 + Math.random()*7);
}
tab.put(value);
notifyAll();
System.out.println(value);
System.out.println("Notified");
}
}
}
}
public class Table {
int value;
public synchronized void put(int n){
this.value = n;
}
public synchronized int remove(){
System.out.println("Value removed" + value);
int temp = value;
value = 0;
return temp;
}
public int contains(){
return this.value;
}
}
package LabTest;
public class Driver {
public static void main(String arg[]){
Table tab = new Table();
Thread ST1 = new Student("S1",4,tab);
Thread ST2 = new Student("S2",2,tab);
Thread ST3 = new Student("S3",1,tab);
Thread Teach = new Teacher("Teacher",tab);
ST1.start();
ST2.start();
ST3.start();
Teach.start();
try {
ST1.join();
ST2.join();
ST3.join();
Teach.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Your code has some fundamental flaws. Both the Teacher and Student classes include synchronized (this) and wait() and notifyAll(), but based on the way you're using them I think you don't really understand that each of these constructs acts only on the specific instance in question.
For instance, when a Student thread enters wait, it will remain in that state until some other thread calls notify() or notifyAll() on that instance.
Very specifically x.notifyAll() doesn't wake up every thread that is doing any kind of waiting. It only wakes up something that has previously done x.wait(), where x is the exact same object.
In order to do this kind of cross thread synchronization, there needs to be a shared object on which all threads act. Since the Table object is shared by all the instances, that seems like the obvious candidate. So for a first pass I would replace all wait() with tab.wait() and notifyAll() with tab.notifyAll() and drop the synchronized(this).
This will likely get you closer to the functionality you're trying to achieve.
Your problem is with this code in your teacher:
int value = 0;
while ((value != 3) && (value != 5) && (value != 6)){
value = (int)(1 + Math.random()*7);
}
So, let us imagine we are the computer:
We set value = 0
We check the while loop condition:
value is not 3 and value is not 5 and value is not 6
We pick another value
Say 1.
value is not 3 and not 5 and not 6
We pick another value
Say 3.
This causes us to exit the while loop.
We notify the students.
Nobody is waiting for 3, 5, or 6 (the only values that will terminate the while loop)
Nobody ever removes a value from the table.
Teacher never generates new values.
Deadlock reached!