JVM在声明并调度新任务后不会终止。

huangapple go评论62阅读模式
英文:

JVM doesn't terminate after a new Task is declared and scheduled

问题

以下是翻译好的代码部分:

public interface Player {
	void sendMessage(String message);
	String getName();
	UUID getUUID();
}

public class HumanPlayer implements Player{
	private final String name;
	private final UUID uuid;
	
	public HumanPlayer(String name, UUID uuid) {
		this.name = name;
		this.uuid = uuid;
	}

	@Override
	public void sendMessage(String message) {
		System.out.println(getName() + " -> " + message);
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public UUID getUUID() {
		return uuid;
	}
	
	static HashMap<UUID, UUID> requests = new HashMap<UUID, UUID>();

	public void request(HumanPlayer target) {
		if(requests.get(uuid) == null) {
			if(requests.get(target.getUUID()) == null) {
				requests.put(uuid, target.getUUID());
				requests.put(target.getUUID(), uuid);
				
				sendMessage("You sent a request to " + target.getName());
				
				new Timer().schedule(new TimerTask() {
					@Override
					public void run() {
						requests.put(uuid, null);
						requests.put(target.getUUID(), null);
						
						sendMessage("Looks like your request timed out.");
						target.sendMessage("Looks like your request timed out.");
					}
				}, 1000L);
			}else {
				sendMessage(target.getName() + " has a request already.");
			}
		}else {
			sendMessage("You have a request already.");
		}
	}
}

public class Main {
	public static void main(String[] args) {
		HumanPlayer p1 = new HumanPlayer("Test", UUID.randomUUID());
		HumanPlayer p2 = new HumanPlayer("Test2", UUID.randomUUID());
		
		p1.request(p2); // Here the request happens properly.
		p1.request(p2); // Here player p1 is notified that p2 has a request already.
	}
}

请注意,代码中的注释和输出信息没有翻译,只提供了代码的翻译版本。如果你需要进一步的解释或讨论,请随时提问。

英文:

Some clarification before we begin, I wrote this code plaintext so excuse some inconsistencies, this is basically some parts of code from my game, in my game players have the ability to send teleport request to one another and the receiving player (of the request) can either deny or accept that request. But I don't want that request to stay in the system forever, so I thought of making a task that will remove the info that "relates" the players.

To start off here is my base Player interface.

public interface Player {
void sendMessage(String message);
String getName();
UUID getUUID();
}

Here is the entire implementation of my Player interface.

public class HumanPlayer implements Player{
private final String name;
private final UUID uuid;
public HumanPlayer(String name, UUID uuid) {
this.name = name;
this.uuid = uuid;
}
@Override
public void sendMessage(String message) {
System.out.println(getName() + &quot; -&gt; &quot; + message);
}
@Override
public String getName() {
return name;
}
@Override
public UUID getUUID() {
return uuid;
}
static HashMap&lt;UUID, UUID&gt; requests = new HashMap&lt;UUID, UUID&gt;();
public void request(HumanPlayer target) {
if(requests.get(uuid) == null) {
if(requests.get(target.getUUID()) == null) {
requests.put(uuid, target.getUUID());
requests.put(target.getUUID(), uuid);
sendMessage(&quot;You sent a request to &quot; + target.getName());
new Timer().schedule(new TimerTask() {
@Override
public void run() {
requests.put(uuid, null);
requests.put(target.getUUID(), null);
sendMessage(&quot;Looks like your request timed out.&quot;);
target.sendMessage(&quot;Looks like your request timed out.&quot;);
}
}, 1000L);
}else {
sendMessage(target.getName() + &quot; has a request already.&quot;);
}
}else {
sendMessage(&quot;You have a request already.&quot;);
}
}
}

What I want you to check specifically is this method.

public void request(HumanPlayer target) {
if(requests.get(uuid) == null) {
if(requests.get(target.getUUID()) == null) {
requests.put(uuid, target.getUUID());
requests.put(target.getUUID(), uuid);
sendMessage(&quot;You sent a request to &quot; + target.getName());
new Timer().schedule(new TimerTask() {
@Override
public void run() {
requests.put(uuid, null);
requests.put(target.getUUID(), null);
sendMessage(&quot;Looks like your request timed out.&quot;);
target.sendMessage(&quot;Looks like your request timed out.&quot;);
}
}, 1000L);
}else {
sendMessage(target.getName() + &quot; has a request already.&quot;);
}
}else {
sendMessage(&quot;You have a request already.&quot;);
}
}

(Another clarification, the HashMap actually is initialized depending on the number of players in the Game e.g. SomePlayerUUID -> null)

Looks like it hangs and doesn't really remove the info from the HashMap.

And for completion this is my Main class.

public class Main {
public static void main(String[] args) {
HumanPlayer p1 = new HumanPlayer(&quot;Test&quot;, UUID.randomUUID());
HumanPlayer p2 = new HumanPlayer(&quot;Test2&quot;, UUID.randomUUID());
p1.request(p2); // Here the request happens properly.
p1.request(p2); // Here player p1 is notified that p2 has a request already.
}
}

Now, what I think might be the problem is that, after the method is run the references of the players are actually eligible for the GC(? probably). I need to somehow pass the player references in for processing, do I create new references or use a lambda expression?

Here is some console output.

Test -&gt; You sent a request to Test2
Test -&gt; You have a request already.
Test -&gt; Looks like your request timed out.
Test2 -&gt; Looks like your request timed out.

BUT the execution doesn't end after that and the Java program keeps "running" I have to forcefully terminate it.

答案1

得分: 1

在Java中,线程有一个名为“daemon”的标志,它告诉JVM在线程运行时是否可以退出。Timer默认创建一个“非守护”线程,这意味着JVM将等待Timer线程停止。

您可以通过向构造函数传递参数来使Timer创建一个守护线程。

new Timer(true).schedule(new TimerTask() {
    ...
}, 1000L);

在您的程序中没有任何东西停止Timer线程。您可以通过调用Timer.cancel方法来请求停止线程。

英文:

In Java, threads have a flag called "daemon" that tells the JVM if it's ok to exit while the thread is running. Timer by default creates a "non-daemon" thread, meaning the JVM will wait for the Timer thread to stop.

You can make Timer create a daemon thread instead, by passing a parameter to the constructor.

new Timer(true).schedule(new TimerTask() {
...
}, 1000L);

Nothing in your program is stopping the Timer thread. You can request to stop the thread by calling the Timer.cancel method.

huangapple
  • 本文由 发表于 2020年7月27日 00:12:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/63102645.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定