I'm currently working on a small game that consisted of a few targets that pop up at random for various amounts of time. The actual game will get it's I/O from a circuit board since the targets are physical.
My problem is that currently I have a java.util.Timer that fire's off every 2 seconds. Once it is triggered a random target will be displayed (which works fine so far). The problem is that I want to display the targets for a random number of seconds between 1-5 whilst the timer is still running and setting off other targets.
I get no errors and the targets display but never disappear. I guess it's some sort of Thread issue and that maybe since I'm using this.* the Target objects are just somehow getting lost in the nether! After searching around the questions here I have come up with this:
public class Target implements Runnable(){
...
public void displayFor(int seconds){
this.display();
Executors.newSingleThreadScheduledExecutor().schedule(this,time,
TimeUnit.SECONDS);
this.setDisplayed(false);
}
#Override
public void run() {
this.destroy();
}
}
Basically the initial game timer (that sets of the Targets display) calls the displayFor(2) method which runs the targets run method after the time passed. The Targets still won't disappear though.
I have tried a number of different ways of doing this like the displayFor() setting off another java.util.Timer and I also had a go at using the Quartz library (which to be honest seemed like overkill anyway) and still can't get it to work. Since there are no error messages I'm really stuck with this one.
I've haven't included a lot of the code because I don't think it's that relevant but if you guys need more information to help just let me know :)
I managed to get it working. Here's the correct code for anyone in a similar situation.
public class Target{
private Timer timer;
...
public void displayFor(int seconds) {
// send the output
BoardInterface.SetDigitalChannel(this.getId());
// calculate the delay
long time = seconds * 1000;
// create a new timer and schedule the new task
timer = new Timer();
timer.schedule(new TargetTimer(this), time);
this.setDisplayed(true);
}
}
class TargetTimer extends TimerTask{
Target target;
public TargetTimer(Target t){
this.target = t;
}
#Override
public void run() {
target.destroy();
}
}
Not sure if this is a good way of doing it but it works. If you notice anything that could be improved please let me know. Thanks guys!
Perhaps you should tell us what the display method does.
Are you un-displaying the target in the destroy/destructor code?
I'd recommend, instead of void display():
public void setDisplayed(boolean display){
if(display) {
///... do appropriate circuit output to turn on target
} else {
/// ... do appropriate circuit output to turn off target
}
}
and of course
public void run(){
setDisplayed(false);
destroy();
}
Related
I'm using Spring Boot for a web server, and there is a scheduled task that I have to run every hour. It involves making thousands of http requests which I have stored in a list (retrieved and set from a different endpoint), which obviously will take long. To speed things up, inside the scheduled method I start up four threads to each handle a fourth of the http calls that I have to make. There is absolutely no risk of deadlock or race-conditions. It's rather simple: I have 1000 http requests to make every hour, thread one will handle the first 250, thread two will handle the next 250, etc.
#Component
public MyComponent {
private List<URI> uris;
...
#Scheduled(fixedRate = 3600000)
public void process() {
List<List<URI>> uriList = //method that will divide up the uri's into equal fourths
uriList.forEach(uri -> new Thread(new URIProcessor(uri)).start());
Would this be an acceptable practice? I know Spring offers its own abstractions for multithreading but I feel such a simple task shouldn't require using them.
one important point to consider, you have configured this process method to run in every 1 hour, however here you don't care what happened to the ones raised before !!
Example:1) Think about this if the previous threads are still running because the URI opening is taking long, in this case you will end up increasing the threads every hour !! So ensure you test that your thread completion time
2) If you thread gets struck say due to technical reason what would you like it to do then ? this needs to be accounted for.
One solution is set a global variable/indicator say a file or database entry to tell new starting process that old is completed else some way to inform you say by logging exceptions or shooting email to you etc...
Please accept and like if you appreciate my gesture to help with my ideas n experience.
You may think of something like this to handle start, stop and restarts
#Component
#Scope("prototype")
public class AutoTimerService {
private ScheduledExecutorService scheduledThreadPool = null;
private Runnable autoTask = null;
private Long currentDelayIntervalInMs;
private boolean isTaskRunning = false;
public AutoTimerService(String name, Long delayIntervalInMs, Runnable autoTask){
if (name == null || name.isEmpty()){
throw new RuntimeException("Please specify a friendly name to the timer service");
}
if (autoTask == null){
throw new RuntimeException("Please specify task to be scheduled of type java.util.TimerTask");
}
this.autoTask = autoTask;
this.currentDelayIntervalInMs = delayIntervalInMs;
}
public synchronized void startTask() {
if (!isTaskRunning) {
scheduledThreadPool = Executors.newScheduledThreadPool(1);;
scheduledThreadPool.scheduleWithFixedDelay(autoTask, 0, currentDelayIntervalInMs, TimeUnit.MILLISECONDS);
isTaskRunning = true;
}
}
public synchronized void resetTask(Long delayIntervalInMs) {
stopTask();
this.currentDelayIntervalInMs = delayIntervalInMs;
startTask();
}
public synchronized void stopTask() {
if (isTaskRunning){
scheduledThreadPool.shutdown();
while(!scheduledThreadPool.isTerminated());
isTaskRunning = false;
}
}
In my app I have 6 Arrays which should be updated each time my main activity starts. They all updated with main thread now and this leads to degradation in my app speed. Here is my dbUpdate() function:
private void dbUpdate(){
dateDB = getDateValues();
valueDB = getValues();
catDB = getCatValues();
catIndexDB = getCatIndex();
catExpenseDB = getCatExpense();
catLimitDB = getCatLimits();
}
These arrays have no dependency on eath other and I want to update them 6 parallel thread. I read this article and tried to put each array get function in a Runnable:
Runnable run6 = new Runnable(){
#Override
public void run(){
catLimitDB = getCatLimits();
}
};
So now I have six Runnable and one Handler and I changed my dbUpdate() function:
private void dbUpdate(){
hand.post(run1);
hand.post(run2);
hand.post(run3);
hand.post(run4);
hand.post(run5);
hand.post(run6);
}
But when I run my app I feel no difference. Can someone help me with this? And I should mention that this is my first experience with multithread programming.
if you really want to run them in parrallel you might do something like this:
new Thread(run1).start();
new Thread(run2).start();
new Thread(run3).start();
..
with the handler.post you add your jobs to a queue to the hanler - and your handler might be configured to run on the UI thread - so this might not be what you want.
I'm trying to make a function which can ONLY be called again after there is some amount of time delay between the two calls, (Say 5 seconds).
I require this functionality for an android app I'm creating.
Since it is possible that the user would be calling that function too frequently within a few seconds, it would destroy his experience. Hence, I'm desperately looking for an answer on this.
public void doSomethin(){
//code here which makes sure that this function has not been called twice within the specified delay of 5 seconds
//Some code here
}
Any help would be awesome!
Adit
You could hold the time in milliseconds and check if the current time is greater than or equal to the previous time + 5 seconds. If it is, execute the method and replace the previous time with the current time.
See System.currentTimeMillis()
public class FiveSeconds {
private static Scanner scanner = new Scanner(System.in);
private static long lastTime = 0;
public static void main(String[] args) {
String input = scanner.nextLine();
while(!input.equalsIgnoreCase("quit")){
if(isValidAction()){
System.out.println(input);
lastTime = System.currentTimeMillis();
} else {
System.out.println("You are not allowed to do this yet");
}
input = scanner.nextLine();
}
}
private static boolean isValidAction(){
return(System.currentTimeMillis() > (lastTime + 5000));
}
}
If the code runs on your main thread, Thread.sleep(5000) is not an option. The easiest way to go then would be:
private long previous = 0;
public void doSomething() {
long now = Calendar.getInstance().getTimeInMillis();
if (now - previous < 5000)
return;
previous = now;
// do something
}
use a static field, which saves the datetime of last execution and before executing check the current datetime against this timestamp.
I won't write code for you but if you think a bit about this it's not that hard. You want to make sure it's not called before 5 seconds has passed since last function call. Let's split this into parts.
1) Get current time
2) Compare to stored time that keeps it value between calls.
3) If less than 5 seconds has passed don't do anything
4) Otherwise store the new value and do stuff.
I never did coding in Android. But if Android has threads (which is most likely, it does). Then within this function sleep the thread for 5 seconds, it means even though it is called, it won't be executed further until 5 seconds are passed
public void doSomething()
{
Thread.sleep(5000); // Please find the corresponding Android method
}
make doSomethin() as a private method.
Expose another function say exposedDoSomething().
public void exposeDoSomething(){
// Add to a queue
}
In a separate thread read the queue in every 5 mins and call doSomethin()
Maybe a TimerTask will help you, more details here:
TimerTask|Android Developers
Example:
private TimerTask tiemrTast= new TimerTask() {
#Override
public void run() {
}
};
And then use this method: public void scheduleAtFixedRate (TimerTask task, long delay, long period)
One problem is that you'll have to have a session level timer for each and every user. This could be a fair amount of overhead depending on how many simultaneous users you have.
It's easy for one user: start a timer on request. It's distinguishing between users that's the problem. Your service is now stateful, which is usually a bad thing. You're giving away idempotence.
You could also maintain state in a database. Don't worry about calls; check persistent operations to make sure they don't happen too frequently.
It's not clear to me whether you mean to exclude all users for five seconds once the method is called by anyone, or if every user is prevented from calling the method again for five seconds once it's called the first time.
This sounds like a throughput killer. I'd reconsider this design.
you can use hander.postDalayed method to call method to run after specific delay
you can use your method something like this
int delay=5000;
int k;
int iDelayTimeInMiliSeconds=2000;
for( k=0;k<arrBatch.size();k++)
{
delay=delay+iDelayTimeInMiliSeconds;
callAllDocumentList(arrBatch.get(k),k,delay);
}
public void callAllDocumentList(final String strInvoiceId,final int count,int delay)
{
mHandler.postDelayed(new Runnable()
{
#Override
public void run()
{
// call your function here that you want to call after specific delay
//getOrderDetails(strInvoiceId,count,true);
}
}, delay);
}
I changed the code to a much more detailed version so you can get a better idea of my problem.
I need to "watch" an integer value and immediately respond to when it changes. So far the best way I've found is using a thread in an infinite loop.
The following is a vastly simplified portion of my project. To summarize, notificationValue is set to 1 by a click of a button within my Bubble class. I need the applet to be able to monitor this notificationValue and respond whenever it changes.
Here is my applet:
public class MyApplet extends JApplet
{
Bubble myBubble = new Bubble();
public void run()
{
new Thread(
new Runnable() {
public void run() {
while(true) {
if(myBubble.getNotificationValue() == 1) {
/* here I would respond to when the
notification is of type 1 */
myBubble.resetNotificationValue;
}
else if(myBubble.getNotificationValue() == 2) {
/* here I would respond to when the
notification is of type 2 */
myBubble.resetNotificationValue;
}
else if(myBubble.getNotificationValue() != 2) {
/* if it is any other number other
than 0 */
myBubble.resetNotificationValue;
}
// don't do anything if it is 0
}
}
}).start();
}
}
And here is my class:
public class Bubble extends JPanel
{
public JButton bubbleButton;
public int notificationValue = 0;
public int getNotificationValue()
{
return notificationValue;
}
public void resetNotificationValue()
{
notificationValue = 0;
}
protected void bubbleButtonClicked(int buttonIndex)
{
notificationValue = buttonIndex;
}
public Bubble()
{
bubbleButton = new JButton();
bubbleButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event)
{
bubbleButtonClicked(1);
}
});
}
}
But obviously that keeps the CPU up at 100% and isn't efficient at all. What would be a better way to do this? (Assume I can't change any of the methods responsible for changing the integer.)
immediately respond to when it changes
How "immediate" does that need to be exactly? Adding a Thread.sleep(10) in your while loop would probably bring down your CPU load to near zero.
What would be a better way to do this? (Assume I can't change any of the methods responsible for changing the integer.)
A better way would be not to expose fields directly. A great example for the benefits of encapsulation - having a setter method would make it trivial to implement the observer pattern.
If that int happens to be a property of a JavaBean, you could use a PropertyChangeListener.
However, I suspect that if you need to monitor some integer for a value change you've got a design problem. It'd be better to make sure that integer can only be changed through some method and make sure that method handles the required logic based on the old and new values.
You could use wait/notify. You could use an ExecutorService. A lot depend on whether you can change the code where the integer is set.
Try adding a Thread.sleep(1); to save CPU.
You can check value of your variable time to time to save CPU. Or use pattern Observer
Could you encapsulate the integer in another class, wrap with a setter and getter and add a notification (via an Observer)?
Assuming you can't change the code which actually sets the integer there isn't much you can do. That being said, if you call Thread.yield() at the end of each pass the impact the thread has on the performance of other applications will be minimal.
I'm writing an application in Java, but need to know how to subtract from a variable once every second. What's the easiest way to do this? Thanks!
The name of the very Java class you need to use to do repeating operations is already sitting there in one of your tags! ;)
While the Timer class will work, I recommend using a ScheduledExecutorService instead.
While their usage is extremely similar, ScheduledExecutorService is newer, more likely to receive ongoing maintenance, fits in nicely with other concurrent utilities, and might offer better performance.
class YourTimer extends TimerTask
{
public volatile int sharedVar = INITIAL_VALUE;
public void run()
{
--sharedVar;
}
public static void main(String[] args)
{
Timer timer = new Timer();
timer.schedule(new YourTimer(), 0, 1000);
// second parameter is initial delay, third is period of execution in msec
}
}
Remeber that Timer class is not guaranteed to be real-time (as almost everything in Java..)
What are you trying to achieve? I would not try relying on the timer to properly fire exactly once per second. I would simply record the start time, and whenever a timer fires, recalculate what the value of the variable should be. Here's how I would do it...
class CountdownValue {
private long startTime;
private int startVal;
public CountdownValue(int startVal)
{
startTime = System.currentTimeMillis();
}
public int getValue()
{
return startVal - (int)((System.currentTimeMillis() - startTime)/1000);
}
}
Use a java.util.Timer to create a TimerTask.