我的服务端对应很多用户,与每一个用户交互都是用的一个线程。用户的功能可以告诉服务端 “是”或者“否”我想在特定场景触发时,服务端让其他用户的功能都disable掉,然后只是enable一个用户的功能,并且只给这个用户30秒时间回答“是/否”,客户回答后,disable这个客户。如果用户超时,没有回答,视为回答否,仍然disable这个客户。我比较迷茫的是,30秒这个怎么做,多线程下有什么好的时钟之类的东西,可以不影响别的线程么,因为有时候是同时enable多个用户,让他们都作答“是否”,什么时钟是只影响当前这一个线程,而且在被通知用户的答案后会自动结束计时的呢。谢谢了!

解决方案 »

  1.   

    你自己为用户创建“计时器“不行吗?时间达到要求后执行其他操作类似下面的写法:import java.awt.*;
    import java.awt.event.*;
    import java.text.SimpleDateFormat;
    import java.util.*;import javax.swing.*;
    import javax.swing.border.*;public class TestTimePieceJFrame extends JFrame {
        ControlPanel controlPane = null; //-----------------控制面板
        JTextField jTextField;    public TestTimePieceJFrame() {
    super();
    init();
        }    private void init() {
    controlPane = new ControlPanel(this);
    add(controlPane);
    setPreferredSize(new Dimension(300, 170));
    pack();
    setVisible(true);
    setResizable(false);
    this.setLocationRelativeTo(null);
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    addKeyListener(new TimePieceKeyListener());
        }    public static void main(String[] args) {
    new TestTimePieceJFrame();
    ;
        }    class TimePieceKeyListener extends KeyAdapter {
    public void keyReleased(KeyEvent e) {
        controlPane.keyReleased(e);
    }
        }
    }
    class ControlPanel extends JPanel {
        private JFrame snakeFrame = null;
        JLabel jLabel,jLabel1, jLabel2, jLabel3, jLabel4;
        Date dateWhenStartJpanel;//保存程序启动时的时间
        Date dateWhenClickF5;
        Thread thread ;
        public ControlPanel(JFrame snakeFrame) {
    super();
    this.snakeFrame = snakeFrame;
    init();
        }    private void init() {
    dateWhenStartJpanel = new Date();
    setSize(608, 31);
    setBackground(Color.WHITE);
    setLayout(new FlowLayout());
    setBorder(new LineBorder(Color.white, 5));
    setLayout(new FlowLayout());
    jLabel = new JLabel();
    jLabel1 = new JLabel();
    jLabel2 = new JLabel();
    jLabel3 = new JLabel();
    jLabel4 = new JLabel();
    add(jLabel);
    add(jLabel1);
    add(jLabel2);
    add(jLabel3);
    add(jLabel4);
    jLabel.setText("F5:开始计时 F6:停止计时");
        }      public void keyReleased(KeyEvent e) {
    int keyCode = e.getKeyCode();
    if (keyCode == KeyEvent.VK_F5) {
        dateWhenClickF5 = new Date();//sava time when click F5
        thread = new Thread(new TimePieceRunnable())
        ;thread.start();
    } else if (keyCode == KeyEvent.VK_F6) {
        if(thread != null)thread.stop();
        else prompt("请先按F5");
    }
        }    class TimePieceRunnable implements Runnable {
    public void run() {
        while (true) {
    Date tempDate = new Date();
    String tempString = formateToTime(tempDate, "现在时间是 E kk:mm:ss:");
    jLabel1.setText(tempString);
    tempString = formateToTime(dateWhenStartJpanel,
    "启动程序时间是 E kk:mm:ss:");
    jLabel2.setText(tempString);

    tempString = formateToTime(dateWhenClickF5,
    "最近一次按动F5时间是 E kk:mm:ss:");
    jLabel3.setText(tempString);
    tempDate = getMillisOfTimeDifference(dateWhenClickF5, tempDate);

    tempString = formateToTime(tempDate,
    "最近一次按动F5到现在的时间差是 kk:mm:ss:");
    jLabel4.setText(tempString);
    try {    
        repaint();
        Thread.sleep(100);////每隔0.1秒刷新一次
    } catch (InterruptedException e) {  
        e.printStackTrace();
    }
        }
    }
        }    public String formateToTime(Date date, String timeRegex) {
    //Date date = new Date();
    //SimpleDateFormat f = new SimpleDateFormat("'BeiJing Time':yyyy年MM月dd日 E kk时mm分ss秒");
    SimpleDateFormat f = new SimpleDateFormat(timeRegex);
    String newTypeDate = f.format(date);
    return newTypeDate;    }    public Date getMillisOfTimeDifference(Date date1, Date date2) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date1);
    long timelnMillis1 = calendar.getTimeInMillis();
    calendar.setTime(date2);
    long timelnMillis2 = calendar.getTimeInMillis();
    calendar.setTimeInMillis(timelnMillis2 - timelnMillis1);
    return calendar.getTime();
        } 
        
        private static int prompt(String promptMessage) {
    return JOptionPane.showConfirmDialog(null, promptMessage, "友情提示",
    JOptionPane.WARNING_MESSAGE);
        }
      
    }
      

  2.   

    因为有时候是同时enable多个用户,让他们都作答“是否”,什么时钟是只影响当前这一个线程,而且在被通知用户的答案后会自动结束计时的呢。目前我们没用Thread类的什么方法, 我不敢用sleep(),因为sleep是static method,会停止当前执行的线程,而我是多线程同时执行,我都不敢确定他要停止哪个线程。我现在用的办法很笨,创建了一个Time对象,然后在各个线程中加入一个循环,不断对比当前时间和起始时间。同时检测用户是否作答。
    我感觉wait可以, 用户做答后用notify, 行么?
      

  3.   

    有一个专门的Timer类啊,直接通过这个来实现就可以了啊
    建议看看API,用法很简单的,和普通线程操作都差不多
      

  4.   

    一个用户使用一个 java.util.concurrent.Future。 Future的 get(30,TimeUnit.SECONDS)
      

  5.   


    有道理,如果我准备好一个boolean answered,在向用户提出问题,等待“是否”答案之前就创建一个Timer,timer的任务定为30秒后把answered设置为yes, 如果用户在这期间回答“是否”,answered也会设置为yes。然后在这个之后用一个while(!answered){},这样只要不作答或者没超时就一直等待。这样子行么?因为这是个多玩家联机的游戏,用while()来检测的话会很慢或者影响游戏么?谢谢了
      

  6.   

    想到了一个新办法: 用lock,创建一个Lock answerLock,在等待答案之前设好一个Timer,30秒后,如果lock没有解除就解除lock,或者玩家回答答案后解除lock。lock一解除后服务端再对客户的答案进行处理。
      

  7.   

    其实也可以用socket.setSoTimeout(30000)这个方法来实现,如果socket在30秒内没有读到任何信息,就会抛出一个SocketTimeoutException,然后你捕获这个异常关闭socket就行了
    import java.io.*;
    import java.net.*;public class Server 
    {
    private ServerSocket server;

    public Server() throws Exception
    {
    server = new ServerSocket(9999);
    while (true)
    {
    Socket socket = server.accept();
    new ListenThread(socket).start();
    }
    }

    public static void main(String[] args) throws Exception
    {
    new Server();
    }

    private class ListenThread extends Thread
    {
    private Socket socket;

    public ListenThread(Socket socket)
    {
    this.socket = socket;
    }

    public void run()
    {
    try
    {
    try
    {
    socket.setSoTimeout(30000); //设置socket超时时间为30秒
    System.out.println("accept " + socket.getInetAddress().getHostAddress() + ":" + socket.getPort());
    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    PrintWriter out = new PrintWriter(socket.getOutputStream());

    out.println("请选择(y/n)");
    out.flush();
    String str = in.readLine();
    if (str.equalsIgnoreCase("y")) //用户选是,启动回显功能
    {
    socket.setSoTimeout(0); //不限制超时时间
    System.out.println(socket.getInetAddress().getHostAddress() + ":" + socket.getPort() + "选择y");
    while ((str = in.readLine()) != null)
    {
    out.println(str);
    out.flush();
    }
    }
    else
    {
    System.out.println(socket.getInetAddress().getHostAddress() + ":" + socket.getPort() + "选择n");
    }
    }
    finally
    {
    System.out.println(socket.getInetAddress().getHostAddress() + ":" + socket.getPort() + "关闭");
    socket.close();
    }
    }
    catch (SocketTimeoutException e) //捕获到超时异常
    {
    System.out.println(socket.getInetAddress().getHostAddress() + ":" + socket.getPort() + "超时");
    try 
    {
    socket.close();
    }
    catch (IOException e1) 
    {}
    }
    catch (Exception e)
    {}
    }
    }
    }
      

  8.   


    有道理啊,不过我发现lock已经解决问题了哈,谢谢了。 我给分了