I just got simple problem, but it seems that I cant find a solution for it. Well the following code is part of open-source project, but this part is written by me from scratch.
Well, everything inside this "script" works well without problems except of one thing,
the int variable CB_State doesn't change after calling StartParticipation() method:
import java.util.Calendar;
import java.util.logging.Logger;
import com.l2jserver.gameserver.Announcements;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
public final class CastleBattle
{
private static Logger _log = Logger.getLogger("CastleBattle");
private static String htm_path = "data/scripts/l2dc/CastleBattle/";
public static int CB_State = 1; // 0 - Disabled, 1 - Not running, 2 - Participation start, 3 - Participation end, 4 - Running, 5 - Event ended
public CastleBattle()
{
CB_Init();
}
// Initialize Engine
private static void CB_Init()
{
if (CB_State == 1)
{
SetStartTime();
}
}
// Event Loop
public static void SetStartTime()
{
Calendar _nextTime = Calendar.getInstance();
int _m = _nextTime.get(Calendar.MINUTE);
int x = 1;
while (_m > 5)
{
_m -= 5;
x++;
}
_nextTime.set(Calendar.MINUTE, x * 5);
ThreadPoolManager.getInstance().scheduleGeneral(new CastleBattleLoop(), _nextTime.getTimeInMillis() - System.currentTimeMillis());
}
// Allow players to participate in the event
public static void StartParticipation()
{
CB_State = 2;
Announcements.getInstance().announceToAll("Castle Battle participation has started.");
_log.info("Castle Battle participation has started.");
}
// Player requests to join event via NPC
public static void CB_bypass(String _cmd, L2PcInstance _player)
{
if (_cmd.startsWith("InitHtmlRequest"))
{
if (CB_State == 0)
{
NpcHtmlMessage _html = new NpcHtmlMessage(0);
_html.setFile("", htm_path + "CB_Disabled.htm");
_player.sendPacket(_html);
}
if (CB_State == 1)
{
NpcHtmlMessage _html = new NpcHtmlMessage(0);
_html.setFile("", htm_path + "CB_NotRunning.htm");
_player.sendPacket(_html);
}
if (CB_State == 2)
{
NpcHtmlMessage _html = new NpcHtmlMessage(0);
_html.setFile("", htm_path + "CB_Participate.htm");
_player.sendPacket(_html);
}
}
}
public static void main(String[] args)
{
_log.info("# Castle Battle Engine #");
_log.info("Author : HyperByter");
_log.info("Version : Beta");
_log.info("Version : 3.7.2013");
new CastleBattle();
}
}
class CastleBattleLoop implements Runnable
{
#Override
public void run()
{
if (CastleBattle.CB_State == 1)
{
CastleBattle.StartParticipation();
}
}
}
So any suggestions how to fix this problem?
The method StartParticipation() is probably never called:
main() calls the constructor of CastleBattle
The CastleBattle constructor calls CB_Init()
CB_Init() calls SetStartTime()
SetStartTime() invokes this line:
ThreadPoolManager.getInstance().scheduleGeneral(new CastleBattleLoop(), _nextTime.getTimeInMillis() - System.currentTimeMillis());
after some whacky and indecipherable arithmetic on _nextTime, it's likely that the schedule interval is either very large, or perhaps negative, either of which may cause the Runnable CastleBattleLoop to never be started, in which case StartParticipation() would never be called.
I don't know what ThreadPoolManager does with strange input, but I would start by debugging what value is being passed into the scheduleGeneral() method and read the javadoc to see what effect such a value would have.
The class at the bottom is called CastleBattleLoop , but it does not contain anything loopy, so StartParticipation() gets called only once (if CB_State is 1 at that moment).
You should add something like
while(running){
if (CastleBattle.CB_State == 1)
{
CastleBattle.StartParticipation();
}
Thread.sleep(100);
}
StartParticipation() is being called inside a thread.
Check if you are trying to figure out its value even before actual change occurs.
[Not sure how are you figuring out the value of "CastleBattle.CB_State" in later part of the code]
Related
Okay so I have tested this code on java 8, 11, and 14, they all have the same result.
This is bad practice and an unrealistic scenario, but I would like to understand the JVM internals that causes this to happen.
If you run this code you will notice that everything except the print part itself of system.out.println inside if execute.
At some point with a slightly different java version I managed to get it to print by changing "play" too volatile, but even that doesn't work now.
Please at least test the code before claiming it is simply deadlocking the variables or using the cache, it is not, the if executes and everything inside it works except the print part itself.
public class Main {
public static void main(String[] args) {
TestClass t = new TestClass();
System.out.println("Starting test");
new MyRunnable(t).start();
while (true)
t.testUpdate(System.currentTimeMillis());
}
}
public class MyRunnable extends Thread {
private TestClass t;
public MyRunnable(TestClass t) {
this.t = t;
}
#Override
public void run() {
try {
Thread.sleep(500L);
t.setPlay(true);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestClass {
private boolean play = false;
private long lastUpdate = 0;
private long updateRate = 2000;
private boolean hasSysoBeenHit = false;
public void testUpdate(long callTime) {
System.out.println(play);
System.out.println((callTime-lastUpdate));
if (this.play && ((callTime-lastUpdate) >= updateRate)) {
System.out.println("Updating! " + (hasSysoBeenHit = true));
this.lastUpdate = callTime;
}
System.out.println("hasbeenhit? " + hasSysoBeenHit);
}
public void setPlay(boolean t) {
System.out.println("Starting game...");
this.play = t;
}
}
Your code is suffering from a data race on the TestClass.play field: there are 2 threads accessing this field and at least one of them does a write. This is already indicated by #aerus.
If you make the field volatile, the data race gets removed. Look for the volatile variable rule in the Java Memory model.
I would also move the logic for the play checking to the begin of the testUpdate method:
public void testUpdate(long callTime) {
if(!play)return;
...
Currently I have a GUI that has options for the user to select on how the program should run:
//Inside GUI.java, start button has clicked -> send all objects to Main class
private void startButtonClicked(MouseEvent e) {
Main.setMain(selectedObj.getItemAt(selectedObj.getSelectedIndex()));
Main.setOwnCar(userName.getText().trim());
Main.enableNaps(weSleep.isSelected());
Main.useOwnHouse(useOwnHouse.isSelected());
if (weSleep.isSelected()) {
Integer minSleep = (Integer) minVal.getValue();
Integer maxSleep = (Integer) maxVal.getValue();
Main.setSleepMinMax(minSleep, maxSleep);
}
setVisible(false);
}
When the start button is clicked I want to pass all the variables from the GUI into the main class. The only way I knew how to do it was to use getter/setters but they have to be static:
static void setSleepMinMax(int min, int max) {
sleepMin = min;
sleepMax = max;
Log("Sleeping debug: [min->" + min + "] [max->" + max + "]");
}
//Inside an infinite loop I have this which is at the top
//until the GUI is closed it does not start the rest of the program
if (gui.isVisible()) {
Log("Waiting for GUI vars");
return 1000;
}
if (!getOwnCar.isEmpty())
Log("Using " + ownerCarName);
Most say avoid static variables. What is the correct way if I am unable to use a constructor because my main class is always running and the GUI is just a window that can be opened to change variables on demand? Perhaps pass by reference similar to C++?
The design it's up to your side. You could pass also the object reference or use some standard design patterns (GOF - singleton).
You could look also at:
Singleton
import java.util.Random;
public class PassVar {
private int mainVar = 0;
private MyObj myobj;
public static void main(String[] args)
{
PassVar pv = new PassVar();
pv.new MyObj(pv);
System.out.println("value="+pv.mainVar);
pv.new ChangeValue(pv);
System.out.println("value="+pv.mainVar);
pv.new ChangeValue(pv);
System.out.println("value="+pv.mainVar);
pv.myobj = pv.new MyObj();
System.out.println("myobj_i="+pv.myobj.i);
pv.new MyObj(pv);
System.out.println("myobj_i="+pv.myobj.i);
pv.new MyObj(pv);
System.out.println("myobj_i="+pv.myobj.i);
}
public void setMainVar(int i)
{
mainVar = i;
}
class ChangeValue
{
ChangeValue(PassVar pv)
{
pv.setMainVar(new Random().nextInt() %100);
}
}
class MyObj
{
public int i=-1;
MyObj() {}
MyObj(PassVar pv)
{
i = 10+new Random().nextInt(10);
pv.myobj = this;
}
}
}
Output:
value=0
value=11 (random between -99 ... 99)
value=77
myobj_i=-1
//set obj.ref. in PassVar from MyObj
myobj_i=18 (random between 10 ... 19)
myobj_i=12
Write it to a property file and read it from there.So that when next time one uses it again he can have the previous values.
I'm going to try to explain this the best I can, and hopefully you can understand my problem.
I'm designing a processor simulation program in Java, and right now I'm currently coding the "clock unit" which is going to control the program's execution. Basically, I have a class ClockUnit that changes state between 0 and 1 periodically. I need a second class Processor to be able to know when the clockunit class changes state, and then executes an instruction. So...
ClockUnit state = 0.
Processor does nothing.
ClockUnit change state = 1.
Processor executes instruction
At the moment I am running the ClockUnit class within a thread, I now need a way to run the Processor class and allow it to constantly check the state of the clock and when it changes to a 1 to execute an instruction. I'm not sure how to do this.
Do I need to create a second thread and run the Processor class from the second thread?
I hope it's clear what I need to happen. In my head its quite a simple task, I just need one thread to constantly check the state of another, but I'm not sure how to go about it.
I have posted my code below. There isn't really much complexity to it.
Main class
public class Main {
private static ALU alu;
private static ClockThread clockThread;
public static void main(String[] args)
{
//two threads, both running at the same time, one thread has clock ticking, other thread gets state of ticking clock and executes on rising edge
alu = new ALU();
clockThread = new ClockThread("clockThread", 1);
clockThread.start();
while(clockThread.getClock().getState() == 1)
{
System.out.println("ON");
}
}
}
ClockThread class
import java.util.Timer;
public class ClockThread extends Thread {
private String threadName;
private double instructionsPerSecond;
private Timer timer;
private Clock clockUnit;
public ClockThread(String name, double insPerSec)
{
threadName = name;
System.out.println("Clock thread initialised");
instructionsPerSecond = insPerSec;
}
public void run()
{
clockUnit = new Clock(instructionsPerSecond);
timer = new Timer();
timer.scheduleAtFixedRate(clockUnit, 0, (long) (clockUnit.timePeriod() * 1000));
}
public Clock getClock()
{
return clockUnit;
}
}
Clock class
import java.util.TimerTask;
public class Clock extends TimerTask{
private int state = 0; //the state of the simulation, instrutions will execute on the rising edge;
private double executionSpeed; //in Hz (instructions per second)
private String threadName = "Clock";
public Clock(double instructionsPerSecond)
{
executionSpeed = instructionsPerSecond;
System.out.println("[Clock] Execution speed set to " + executionSpeed + "Hz. (" + timePeriod() + "s per instruction.)");
}
public void run()
{
toggleState();
System.out.println("System State: " + state);
}
public void toggleState()
{
if(state == 1)
{
state = 0;
}
else if(state == 0)
{
state = 1;
}
}
public double timePeriod() //takes the number of instructions per second (hz) and returns the period T (T = 1/f);
{
double period = 1/executionSpeed;
return period;
}
public double getExecutionSpeed()
{
return executionSpeed;
}
public int getState()
{
return state;
}
}
Since you already have a reliable clock source (the producer), you can use a BlockingQueue to send 'EdgeChange' alerts to the ALU? (the unit responsible for executing instructions). The clock source will 'offer' the edge change event, and the ALU? will receive it (and subsequently do work). Here is the slight changes to your code to share events across objects in different threads:
Main:
public static void main(String[] args) {
BlockingQueue<Integer> edgeAlerts = new ArrayBlockingQueue<Integer>(2);
clockThread = new ClockThread("clockThread", 1, edgeAlerts);
clockThread.start();
boolean isInterrupted = false;
while(!isInterrupted) {
try {
Integer edgeValue = edgeAlerts.take();
if (edgeValue == 1) {
System.out.println("Executing instruction");
// Perform the instruction
}
} catch (InterruptedException e) {
isInterrupted = true;
}
}
}
You have to pass the BlockingQueue to your ClockThread ...
private final BlockingQueue<Integer> edgeAlerts;
public ClockThread(String name, double insPerSec, BlockingQueue<Integer> edgeAlerts)
{
threadName = name;
this.edgeAlerts = edgeAlerts;
System.out.println("Clock thread initialised");
instructionsPerSecond = insPerSec;
}
And to your Clock:
private final BlockingQueue<Integer> edgeAlerts;
public Clock(double instructionsPerSecond, BlockingQueue<Integer> edgeAlerts)
{
this.edgeAlerts = edgeAlerts;
executionSpeed = instructionsPerSecond;
System.out.println("[Clock] Execution speed set to " + executionSpeed + "Hz. (" + timePeriod() + "s per instruction.)");
}
And your clock run becomes:
public void run()
{
toggleState();
System.out.println("System State: " + state);
edgeAlerts.offer(state);
}
Let me know if this works for you.
So here's my situation:
I got a few Threads that should do background work, ideally with a ThreadPool/ExecutorService and such
There are a lot of Runnables generated regularly that call one long method. They should be processed by the background workers.
The runnables have an order they should be executed in (approximately). The interesting thing is: that ordering is dynamic and might change at any time. So which runnable to take next should be decided as late as possible, directly before running it.
It should be possible to stop all currently working runnables. If this is not possible, they should be notified so that they discard their work once it's finished.
I don't really know how to approach this problem, and I'm not really familiar with multithreading and Java's APIs in that matter.
About the ordering
What I mean with approximately in order: if they get started in order, it will be good enough. Each Runnable does some work on a tile of a map. The idea is to sort the runnables in such a way, that tiles near the position where the used is looking at will be loaded first and then loading the surroundings. Note that therefore the order of execution might change at any time.
One solution is to put all the jobs that you want to process into a PriorityBlockingQueue. (This queue is automatically sorted either using the natural ordering of the queue items or by providing a Comparator). then the threads running within the ExecutorService should just take elements from the queue.
for example
import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
public class PriorityQueueExample {
public static void main(String[] args) throws InterruptedException {
PriorityQueueExample priorityQueueExample = new PriorityQueueExample();
priorityQueueExample.doTheWork();
}
private void doTheWork() throws InterruptedException {
PriorityBlockingQueue<Customer> queue = new PriorityBlockingQueue<>(10, new CustomerComparator());
queue.add(new Customer("John", 5));
queue.add(new Customer("Maria", 2));
queue.add(new Customer("Ana", 1));
queue.add(new Customer("Pedro", 3));
while(queue.size() > 0){
System.out.println(queue.take());
}
}
}
class CustomerComparator implements Comparator<Customer> {
#Override
public int compare(Customer o1, Customer o2) {
return o1.getUrgency() - o2.getUrgency();
}
}
class Customer {
private String name;
private int urgency;
public Customer(String name, int urgency) {
this.name = name;
this.urgency = urgency;
}
public String getName() {
return name;
}
public int getUrgency() {
return urgency;
}
#Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", urgency=" + urgency +
'}';
}
}
1) Have your tiles implements Callable. You can have them return Callable too.
2) Determine which ones are position to be loaded first.
3) Pass them or their Callables into java.util.concurrent.ExecutorService.invokeAll.
4) Once invokeAll is returned get the next set of tiles adjacent to the previous ones and call java.util.concurrent.ExecutorService.invokeAll again.
5) Repeat step 4 if necessary.
you could also use a List to emulate a priority queue. For example:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListEmulateQueueExample {
public static void main(String[] args) throws InterruptedException {
ListEmulateQueueExample priorityQueueExample = new ListEmulateQueueExample();
priorityQueueExample.doTheWork();
}
/**
* uses a list to emulate a queue.
*/
private void doTheWork() {
List<Customer> customerList = Collections.synchronizedList(new ArrayList<>());
Customer johnCustomer = new Customer("John", 5);
Customer mariaCustomer = new Customer("Maria", 3);
Customer anaCustomer = new Customer("Ana", 1);
customerList.add(johnCustomer);
customerList.add(mariaCustomer);
customerList.add(anaCustomer);
CustomerComparator customerComparator = new CustomerComparator();
synchronized (customerList){
customerList.sort(customerComparator);
}
System.out.println(customerList.remove(0)); // Ana
johnCustomer.setUrgency(1);
synchronized (customerList){
customerList.sort(customerComparator);
}
System.out.println(customerList.remove(0)); // John
}
}
So, I finally got a way around this problem. It's not that beautiful and kind of a hack, but it works as intended.
The idea is: if every Runnable is stateless and does only call one method, it does not need to know the tile it should work on on creation. Instead, it will ask for a needed tile once it's started.
public class WorldRendererGL {
protected Map<Vector2i, RenderedRegion> regions = new ConcurrentHashMap<>();
protected Queue<RegionLoader> running = new ConcurrentLinkedQueue<>();
protected Set<RenderedRegion> todo = ConcurrentHashMap.newKeySet();
protected ExecutorService executor;
/** Recalculate everything */
public void invalidateTextures() {
//Abort current calculations
running.forEach(f -> f.invalid.set(true));
running.clear();
todo.addAll(regions.values());
for (int i = 0; i < regions.size(); i++) {
RegionLoader loader = new RegionLoader();
running.add(loader);
executor.submit(loader);
}
}
protected class RegionLoader implements Runnable {
/** Set this to true to nullify all calculations*/
final AtomicBoolean invalid = new AtomicBoolean(false);
#Override
public void run() {
try {
if (invalid.get())
return;
RenderedRegion region = null;
region = nextRegion(); // Get the correct work at runtime
if (region == null)
return;
BufferedImage texture = renderer.renderRegion(new RegionFile(region.region.regionFile));
if (!invalid.get()) {
region.texture = texture;
update.notifyObservers();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
protected RenderedRegion nextRegion() {
Comparator<RenderedRegion> comp = (a, b) -> /*...*/);
RenderedRegion min = null;
for (Iterator<RenderedRegion> it = todo.iterator(); it.hasNext();) {
RenderedRegion r = it.next();
if (min == null || comp.compare(min, r) > 0)
min = r;
}
todo.remove(min);
return min;
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have the following code, but I want it to run once every second, so if questNumber changes, then currentQuestStats will also change.
Editor's note: pastebin link with code that used to be here no longer works.
use ScheduledExecutorService which added in JAVA 5, you must import following classes.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
you can use it like below:
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// TODO add your code here:
}
}, 0, 1, TimeUnit.SECONDS);
Answer
make a method called checkQuestNumber() in QuestsManagement class.
also create a constructor for QuestsManagement
initialize currentQuestStats with this value (§e§lCurrent quest: Kill 1 zombie).
make currentQuestStats and questNumber private and encapsulate them.
here is your QuestsManagement after those changes
public class QuestsManagement {
private String currentQuestStats = "§e§lCurrent quest: Kill 1 zombie";
private int questNumber = 1;
public String getCurrentQuestStats() {
return currentQuestStats;
}
public int getQuestNumber() {
return questNumber;
}
QuestsManagement() {
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
checkQuestNumber();
}
}, 0, 1, TimeUnit.SECONDS);
}
void checkQuestNumber() {
if (questNumber == 1) {
currentQuestStats = "§e§lCurrent quest: Kill 1 zombie";
// change manual!
questNumber = 2;
} else if (questNumber == 2) {
currentQuestStats = "§e§lCurrent quest: Walk 100 blocks";
// change manual!
questNumber = 1;
}
}
}
To Test Code!
in your custom command file
create an instance of QuestsManagement and use getCurrentQuestStats() method
QuestsManagement m = new QuestsManagement();
player.addChatMessage("Test" + QuestsManagement.getCurrentQuestStats());
Do it using multithreading. Here's the code:
public class QuestsManagement implements Runnable{
public String currentQuestStats = "";
public int questNumber = 1;
Thread t;
#Override
public void run() {
try {
if(questNumber == 1) {
currentQuestStats = "§e§lCurrent quest: Kill 1 zombie";
if(questNumber == 2) {
currentQuestStats = "§e§lCurrent quest: Walk 100 blocks";
}
}
Thread.sleep(1000);
}
catch(Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
Thread t = new Thread(new QuestsManagement());
t.start();
//do something else here... whatever you want to do
}
}
First of all, you need to add all of the code you want to run to a method. I will assume you will call it update().
What you then want to do is add something like the following to your main program loop:
long nextTick = currentTimeMillis() + 1000 ;//Set time of first game tick
QuestsManagement quest = new QuestsManagement();
//Main Loop
while (true) {
/*
Do some other stuff
*/
if (System. currentTimeMillis() >= nextTick) {//Check to see if it is time or past time to update
nextTick += 1000//Set next tick to one second in the future
quest.update();
}
}
Please note that you are missing the update() method, the constructor, and any getters and setters. I would also refrain from making your variables public.
Well, there are multiple answers possible to this question. Java provides various ways to perform time operations. One approach is to use Timer class.
public class QuestsManagement {
public String currentQuestStats = "";
public int questNumber = 1;
static Timer t;
TimerTask task;
public static void main(String[] args) {
t = new Timer();
task = new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
if(questNumber == 1) {
currentQuestStats = "§e§lCurrent quest: Kill 1 zombie";
if(questNumber == 2) {
currentQuestStats = "§e§lCurrent quest: Walk 100 blocks";
}
} ;
t.scheduleAtFixedRate(task , 1000, 1000 );
}}
import following
import java.util.Timer;
import java.util.TimerTask;