【发布时间】:2015-03-02 03:36:47
【问题描述】:
我(希望是最后一个)关于 Java 中的定时事件和线程的问题。我有一个服务器应用程序,它向所有客户端发送有关当前服务器时间的信息。我为客户端添加了更改服务器时间的可能性。但是,按照目前的实现方式,每个客户端连接都在单独的线程上运行。每个线程都有自己的 ClockTask 实例。所以即使时间被客户端修改,也只会在这个特定线程的 ClockTask 实例中被修改。任何其他客户仍将拥有自己的旧时光。我的代码:
服务器 - 每次传入客户端连接时,都会启动一个新线程。
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listeningSocket = true;
try {
serverSocket = new ServerSocket(11111);
} catch (IOException e) {
System.err.println("Could not listen on port: 11111");
}
while(listeningSocket){
System.out.println("Waiting for a client to connect...");
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected!");
ConnectThread ct = new ConnectThread(clientSocket);
ct.start();
}
System.out.println("closed");
serverSocket.close();
}
}
ConnectThread - 每个连接线程都有自己的 ClockTask(实际上是一个计时器,每秒更新一次时间):
public class ConnectThread extends Thread{
public static final int INTERVAL = 1000;
static ClockTask ctask;
private Socket socket = null;
public ConnectThread(Socket socket) {
super("ConnectThread");
this.socket = socket;
if(this.ctask == null)
{
synchronized(ClockTask.class)
{
if(this.ctask == null)
{
this.ctask = new ClockTask();
}
}
}
}
@Override
public void run(){
ObjectOutputStream serverOutputStream = null;
ObjectInputStream serverInputStream = null;
try {
serverOutputStream = new ObjectOutputStream(socket.getOutputStream());
serverInputStream = new ObjectInputStream(socket.getInputStream());
Timer timer = new Timer();
timer.schedule(ctask, 0, INTERVAL);
while(true)
{
Thread.sleep(INTERVAL);
System.out.println("mark");
System.out.println(ctask.getTime());
serverOutputStream.writeUTF(ctask.getTime());
serverOutputStream.flush();
String ok = serverInputStream.readUTF();
if(ok.equals("ok"))
{
String newTime = serverInputStream.readUTF();
ctask.setCalendarTime(newTime);
}
}
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
try {
serverOutputStream.close();
serverInputStream.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
时钟任务持有时间信息:
public class ClockTask extends TimerTask {
private Calendar calendar;
private String time;
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public ClockTask()
{
this.calendar = Calendar.getInstance(new Locale("us", "US"));
}
@Override
public void run() {
calendar.add(Calendar.SECOND, 1);
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
this.time = dateFormat.format(calendar.getTime());
//System.out.println(time);
}
public void setCalendarTime(String newTime)
{
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
try {
Date t = dateFormat.parse(newTime);
calendar.setTime(t);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
现在,我想到的第一个明显方法是在 Server 类中声明 ClockTask,然后将对象引用传递给任何新的 ConnectThread,然后对其进行修改。但这不起作用,我有很多数据读取错误,还有一个问题是它发生在静态主方法中,所以我只能以静态方式访问它。我唯一知道的是,它不能在每个新的 ConnectThread 实例中创建。它必须是一个物体,存在于外部某处。有什么想法吗?
编辑 客户:
public class Client {
private static final String REQUEST_TIME_CHANGE = "ok";
public static void main(String[] arg) {
Socket socketConnection = null;
ObjectOutputStream clientOutputStream = null;
ObjectInputStream clientInputStream = null;
ClockGUI gui = new ClockGUI();
gui.setVisible(true);
try {
socketConnection = new Socket("127.0.0.1", 11111);
clientOutputStream = new ObjectOutputStream(
socketConnection.getOutputStream());
clientInputStream = new ObjectInputStream(
socketConnection.getInputStream());
while(true){
System.out.println("before\n");
String date = clientInputStream.readUTF();
System.out.println(date);
gui.cp.setDate(date);
gui.repaint();
if(gui.isTimeChanged())
{
clientOutputStream.writeUTF(REQUEST_TIME_CHANGE);
clientOutputStream.flush();
clientOutputStream.writeUTF(gui.getTime());
clientOutputStream.flush();
gui.setTimeChanged(false);
}
else{
clientOutputStream.writeUTF("");
clientOutputStream.flush();
}
}
} catch (Exception e) {
System.out.println("The following exception has occured and was caught:");
e.printStackTrace();
}
finally{
try {
clientOutputStream.close();
clientInputStream.close();
socketConnection.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
【问题讨论】:
-
你为什么不使用
ScheduledExecutorService? -
嗯,主要是因为我不知道它的存在;)它有什么更好的地方?
-
好吧,你可以用它来安排“任何你想要的”;此外,它对系统时钟变化不敏感
标签: java multithreading time client server