i am trying to simulate visitors going into a theater and taking an aailable sit(the number of available sits is shared) and once all the sits are taken the rest go to sleep.
i am having trouble over the availablesits variable in the getsit method inside the visitor class.
please help me
i tried synchronizing the threads as well as making the variable volatile. but for some reasons all threads arrive to that getsit part at the same time? i dont understand why!
//main
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
int numVisitors = 23;
int theaterCapacity =5;
int party_ticket=3;
Clock clock = new Clock();
Theater theater=new Theater(theaterCapacity,clock);
ArrayList<Visitor> visitorlist = new ArrayList<Visitor>();
for(int i=1;i<=numVisitors;i++) {
visitorlist.add(new Visitor(i,clock,theater));
}
clock.start();
for(Visitor visitor:visitorlist)
visitor.start();
}
}
//visitor class
public class Visitor extends Thread{
private static Clock clock;
private static Theater theater;
public int id;
public boolean sawPresentation=false;
public volatile int priority= 10;
public static long time = System.currentTimeMillis();
public void msg(String m) {
System.out.println("["+(System.currentTimeMillis()-time)+"] "+getName()+": "+m);
}
Visitor(int id, Clock clock, Theater theater){
this.id=id;
this.clock=clock;
this.theater=theater;
}
public void run(){
heArrives();
while(!sawPresentation) {
while(!clock.presentationIsOpen()) {
//busy wait
}
getASit();
}
}
public void heArrives() {
msg("the visitor arrived");
}
public synchronized void getASit(){
if(theater.availableSits>0){
msg("the visitor got a sit");
theater.availableSits--;
watchPresentation();
}
}
public void watchPresentation(){
msg("the visitor is watching the presentation");
}
}
//clock class
import java.util.Timer;
import java.util.TimerTask;
public class Clock extends Thread {
public static long time = System.currentTimeMillis();
public static int secondsPassed=6;
Timer timer= new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
secondsPassed++;
//System.out.println("seconds passed: "+secondsPassed);
}
};
public void run(){
timer.scheduleAtFixedRate(task,0,1000);
}
public boolean presentationIsOpen(){
if(secondsPassed%6==0) return true;
return false;
}
}
//theater class
class Theater extends Thread{
public static Clock clock;
public int capacity;
public volatile int availableSits=5;
Theater(int capacity,Clock clock){
this.capacity=capacity;
this.clock=clock;
}
}
Your main problem is the synchronization of the getASit method.You are synchronizing against Visitor object instance so every thread synchronized against diferent object. Instead you have to synchronized against the object that is shared. In your case against the theater. Change your method to something like this:
public void getASit(){
synchronized(theater){
if(theater.availableSits>0){
msg("the visitor got a sit");
theater.availableSits--;
watchPresentation();
}
}
}
Its better not to use busy wait, its burn cpu too much, better is to use sleep for example:
while(!clock.presentationIsOpen()) {
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Related
I looked around and seemed similar code but mine is not working. My volatile variable is chaning in the class clock but my class vistor is not getting the changed variable. I will post my code. If theres a similar queston please link. Thank you for the help.
I tried by setting the declarations in all my classes for the volatile boolean variables to false. It didn't help.
public class Main {
volatile static boolean isInSession;
volatile static boolean sessionOver;
public static void main (String [] args)
{
for (int i = 0; i < 25; i++) {
Visitor visitor = new Visitor(i, isInSession);
visitor.start();
}
Thread clock = new Thread(new Clock(isInSession, sessionOver));
clock.start();
}
}
public class Visitor extends Thread {
volatile static boolean isInSession;
private int visitorId;
volatile static int seats = 5;
Visitor(int visotrId, boolean isInSession)
{
this.isInSession = isInSession;
setName("visitorId " + visitorId);
}
#Override
public void run() {
while(true)
{
while(isInSession){}
System.out.println("In visitor isInSession " + isInSession);
if(isInSession)
System.out.println("Visitor isInSession " + isInSession);
try {
Thread.currentThread().sleep(5000);
}
catch(InterruptedException e)
{ }
}
}
public void msg(String m) {
System.out.println("["+(System.currentTimeMillis()-time)+"]
"+getName()+": "+m);
}
}
public class Clock implements Runnable {
volatile static boolean isInSession;
volatile static boolean sessionOver;
private int session = 0;
public Clock(boolean isInSession, boolean sessionOver)
{
this.isInSession = isInSession;
this.sessionOver = sessionOver;
}
#Override
public void run() {
while(true)
{
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
}
isInSession = false;
msg("Theater is open");
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
}
isInSession = true;
//System.out.println("In clock isInSession " + isInSession);
session++;
}
}// end of run
public void msg(String m) {
System.out.println("["+(System.currentTimeMillis()-time)+"]" +"Clock:
"+ m);
}
}
You can use AtomicBoolean for your purpose.
As JB Nizet has pointed out, arguments in Java are passed-by-value. Here's an answer on another SO post that explains this in detail.
For your purpose, it suffices to know that, "when we pass the value of an object, we are passing the reference to it" (a quote from the SO post mentioned above). By creating an AtomicBoolean object and passing it to both the Clock and Visitor objects, when Clock updates the value of the AtomicBoolean, the Visitor objects will receive the updated value too.
So, your main class should look like this:
public class Main {
static AtomicBoolean isInSession = new AtomicBoolean(); // default value is false
static AtomicBoolean sessionOver = new AtomicBoolean();
public static void main (String [] args)
{
for (int i = 0; i < 25; i++) {
Visitor visitor = new Visitor(i, isInSession);
visitor.start();
}
Thread clock = new Thread(new Clock(isInSession, sessionOver));
clock.start();
}
}
To access the value of the AtomicBoolean in Visitor or to update the value in Clock, you can use the get() and set(boolean) method respectively.
I've got a problem as follows: I've got the next class:
Public class foo{
Thread runningThread = null;
...
public static void start() {
runningThread = new RunningThreadImpl();
runningThread.start();
runningThread.join();
}
public static void stop() {
this.runningThread.stop();
}
}
And:
Public class runningThreadImpl implements Runnable {
...
public void run() {
while (shouldRun()){
sleep(... A long long time);
}
}
public void stop() {
shouldRun = false;
}
I've got a class using foo, And now i want it to stop. The above code defined inside a given jar, Which means i cannot edit it. But i thought about using Reflection in order to interrupt the Thread and "Wake" him up so i won't have to wait.
So far i've gotten this far:
Field field = foo.getInstance().getClass().getDeclaredField("runningThread");
field.setAccessible(true);
But i don't now what to do now. How can i use the Field in order to interrupt a thread? Is it even possible?
You could create a new class called FooHelper in the same package as Foo like so:
package same.package.as.foo;
public class FooHelper {
private final Foo foo;
public FooHelper(Foo foo) {
this.foo = foo;
}
public void stop() {
this.foo.stop();
this.foo.runningThread.interrupt();
}
}
Construct a FooHelper passing it the instance of Foo, and call the FooHelper's stop() method.
trying to make an lru map by subclassing linked hash map.
the map is run through collections.synchronized.
all usages of the map are surrounded by a synchronized block. the unit test also fails if they are all removed. one would think they are not necessary since the map was run through collections.synchronized.
one thread puts sequential numbers (0,1,2,3 ...) into the map. removals are handled by removed eldest entry. no one else removes entries from the map.
the other thread gets the data from the map.
the following unit test fails usually at "oops". this is when a non zero number shows up in the first position (it should be zero until the map gets full). other strange things can happen like null values in the entry set.
any pointers will be appreciated.
thanks
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
class LruMap<K,V> extends LinkedHashMap<K,V> {
public LruMap() {
super(defaultMaxSize+1,.75f,true);
maxSize=defaultMaxSize;
}
public LruMap(int arg0) {
super(arg0+1,.75f,true);
maxSize=arg0;
}
public LruMap(int arg0,float arg1) {
super(arg0+1,arg1,true);
maxSize=arg0;
}
public LruMap(int arg0,float arg1,boolean arg2) {
super(arg0+1,arg1,arg2);
if(!arg2)
throw new RuntimeException("you did not construct an lru map!");
maxSize=arg0;
}
public LruMap(Map<K,V> arg0) {
super(arg0);
throw new RuntimeException("you did not construct an lru map!");
}
public boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size()>maxSize;
}
public final int maxSize;
public static final int defaultMaxSize=2048;
static final long serialVersionUID=0;
}
class Server implements Runnable {
public Server(final int pieces,final int period) {
this.pieces=pieces;
this.period=period;
lruMap=Collections.synchronizedMap(new LruMap<Long,Long>(3*pieces/2));
}
#Override public void run() {
t0=System.currentTimeMillis();
while(piece<stopAtPiece) {
final long dt=System.currentTimeMillis()-t0;
final long target=piece(dt);
System.out.println("adding "+(target-piece+1)+" items");
for(;piece<=target;piece++) {
synchronized(lruMap) {
lruMap.put(piece,piece);
}
}
checkMap(piece,true);
try {
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
break;
}
}
}
Map.Entry<Long,Long>[] checkMap(final long n,boolean print) {
synchronized(lruMap) {
Map.Entry<Long,Long>[] entries=null;
if(lruMap.size()>0) {
final Set<Map.Entry<Long,Long>> entrySet=lruMap.entrySet();
entries=new Map.Entry[entrySet.size()];
entrySet.toArray(entries);
long first=entries[0].getKey();
long last=entries[entries.length-1].getKey();
if(print)
for(Map.Entry<Long,Long> entry:entries)
System.out.print(entry.getKey()+" ");
System.out.println();
if(n<pieces&&first!=0) {
System.out.println("lru: first!=0! "+first);
if(throwWhenfirstIsNotZero) { throw new RuntimeException("oops"); }
}
for(int i=0;i<entries.length-1;i++) {
long p0=entries[i].getKey();
long p1=entries[i+1].getKey();
if(p0>p1)
System.out.println("out of order! "+p0+" "+p1);
else if(p0==p1)
System.out.println("dupicate "+p0+" "+p1);
else if(p0+1==p1)
; // ok
else if(p0+1<p1)
System.out.println("skipped "+p0+" "+p1);
else System.out.println("some case i mssed!");
}
}
return entries;
}
}
public long piece(final long dt) {
return dt/period*pieces+dt%period*pieces/period;
}
public boolean throwWhenfirstIsNotZero=true;
protected long piece;
public long t0;
protected long stopAtPiece=Long.MAX_VALUE;
public final int period;
public final int pieces;
public final Map<Long,Long> lruMap;
}
public class ServerTestCase {
#Before public void setUp() throws Exception {}
#After public void tearDown() throws Exception {}
#Test public void testRun() {
server.stopAtPiece=server.pieces;
server.throwWhenfirstIsNotZero=true;
Thread thread=new Thread(server);
thread.setName("server");
thread.start();
while(thread.isAlive()) {
for(long i=0;i<server.piece;i++)
synchronized(server.lruMap) {
server.lruMap.get(i);
}
}
}
final int period=2*1000;
final int serverPieces=100;
Server server=new Server(serverPieces,period);
}
If you are accessing the collection inside a synchronized(lruMap) block, then you probably don't want to wrap it in Collections.synchronizedMap() - use one or the other. This is because they will probably be using different locks - in fact it's almost certain, because it's extremely unlikely that synchronizedMap() is using synchronized(this) internally.
Also I recommend enter link description here
Suppose I have a class like this:
package com.spotonsystems.bulkadmin.cognosSDK.util.Logging;
public class RecordLogging implements LittleLogging{
private LinkedList <String> logs;
private boolean startNew;
public RecordLogging() {
logs = new LinkedList<String>();
}
public void log(String log) {
logHelper(log);
startNew = true;
}
public void logPart(String log) {
logHelper(log);
startNew = false;
}
private void logHelper(String log){
// DO STUFF
}
public LinkedList<String> getResults() {
return logs;
}
}
Now suppose that I need a thread safe version of this code. I need the tread safe version to implement LittleLogging. I want the thread safe copy to have the same behavior as this class except I would like it to be thread safe. Is it safe to do this:
package com.spotonsystems.bulkadmin.cognosSDK.util.Logging;
public class SyncRecordLogging extends RecordLogging {
public SyncRecordLoging() {
super();
}
public syncronized void log(String log) {
super.log(log);
}
public syncronized void logPart(String log) {
super.log(log);
}
public syncronized LinkedList<String> getResults() {
return logs;
}
}
Bonus Question: Where should I look for documentation about syncronization and threading
You can use composition instead. Also note that getResults creates a copy of the list:
public class SyncRecordLogging implements LittleLogging{
private final RecordLogging _log;
public SyncRecordLogging() {
_log = new RecordLogging();
}
public synchronized void log(String log) {
_log.log(log);
}
public synchronized void logPart(String log) {
_log.logPart(log);
}
public synchronized LinkedList<String> getResults() {
// returning copy to avoid 'leaking' the enderlying reference
return new LinkedList(_log.getResults());
}
}
Best read: Java Concurrency In Practice
Basically, I have an int value, x, that is an instance variable of a class. It is set to 0 initially. I have another method, "getNum," that increments and returns x. This getNum() method is called by an outside program. However, each day (let's say, at midnight, for simplicity's sake) I want to reset x to 0. How would this be done? The problems I'm having now: Date(int, int, int) is deprecated but the method only takes Dates, not Calendars; the TimerTask event never happens; every time I run the program at the bottom, it simply prints "0" every time even though the number should not be constantly resetting. Basically, nothing works. Any ideas what is going wrong?
import java.util.*;
class Foo {
private static void scheduleTimer() {
Timer timer = new Timer();
long c = 86400000;
timer.scheduleAtFixedRate(new MyTimerTask(),
new Date(2011, 7, 31), c);
}
public static int getNum() { return x++; }
private static int x = 0;
public static void resetNum() { x = 0; }
}
class MyTimerTask() extends TimerTask {
public void run() {
Foo.resetNum();
}
public class Bar { // in a separate file
public static void main (String[] args) {
System.out.println(Foo.getNum());
}
}
Fix your two compilation errors, call Foo.scheduleTimer() somewhere to actually start the timer, give the timer a reasonable delay and period (like a few seconds), and then call Foo.getNum() repeatedly instead of just once. For example:
import java.util.Timer;
import java.util.TimerTask;
public class Foo {
public static void scheduleTimer() {
Timer timer = new Timer();
long c = 3000;
timer.scheduleAtFixedRate(new MyTimerTask(), c, c);
}
public static int getNum() { return x++; }
private static int x = 0;
public static void resetNum() { x = 0; }
}
class MyTimerTask extends TimerTask {
public void run() {
Foo.resetNum();
}
}
class Bar {
public static void main(String[] args) throws Exception {
Foo.scheduleTimer();
while (true) {
System.out.println(Foo.getNum());
Thread.sleep(1000);
}
}
}
Per the documentation for scheduleAtFixedRate(TimerTask, Date, long):
Schedules the specified task for repeated fixed-rate execution,
beginning at the specified time. Subsequent executions take place at
approximately regular intervals, separated by the specified period.
So it would take roughly 86400000 milliseconds for your task to be called. Are you actually waiting that long to confirm it is not working?