Я программирую сетевой одноэлементный класс, и он должен запускаться в потоке, до сих пор нет проблем, однако я не могу заставить его работать печально.java singleton network реализация runnable
Сеть Класс:
public class Network extends Thread {
private static Network cachedInstance = new Network();
private PrintWriter out;
private BufferedReader in;
private Network() {
}
private void init() {
try {
Socket clientSocket = new Socket(Config.HOST_NAME, Config.HOST_PORT);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String fromServer;
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
}
} catch (IOException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static Network getInstance() {
return cachedInstance;
}
public void send(final String string) {
out.println(string);
}
@Override
public void run() {
init();
}
}
Часть класса контроллера:
public void clientTest() {
int random = new Random().nextInt(1000);
Network.getInstance().start();
Network.getInstance().send(random + "");
}
Ошибка я получаю:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at network.Network.send(Network.java:52)
at controller.Controller.clientTest(Controller.java:126)
Так выглядит как один экземпляр сети не правильно созданный, что теоретически не должно быть возможным.
Второй вопрос у меня есть, если я могу избежать использования этого:
Network.getInstance().start();
Другими словами, я хотел бы, чтобы гарантировать, что только один поток (Network класс) создается и что он всегда работает по умолчанию когда классы инициализируются. Это не плохо в нынешнем виде, но я просто подумал, что было бы лучше.
Для людей, интересующихся, почему я использую этот подход: в основном я хочу использовать Network.send() для отправки на фиксированный сервер. Разумеется, этот сервер также может отправить сообщение обратно, но на этой сети в какой-то момент необходимо реагировать и вызывать методы из контроллера.
С уважением.
EDIT: Предлагаемое решение, основанное на реакциях
Network.class:
public class Network implements Runnable {
private static final Network cachedInstance;
static {
Network tempInstance = null;
try {
tempInstance = new Network(Config.HOST_NAME, Config.HOST_PORT);
} catch (IOException ex) {
Logger.getLogger(Network.class.getName()).log(Level.SEVERE, null, ex);
} finally {
cachedInstance = tempInstance;
}
}
private final Socket clientSocket;
private final PrintWriter out;
private final BufferedReader in;
private Network(final String hostname, final int port) throws IOException {
clientSocket = new Socket(hostname, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
public static Network getInstance() {
return cachedInstance;
}
@Override
public void run() {
try {
String fromServer;
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
}
} catch (IOException ex) {
Logger.getLogger(Network.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void send(final String string) {
out.println(string);
}
public void close() {
try {
in.close();
out.close();
clientSocket.close();
} catch (IOException ex) {
Logger.getLogger(Network.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
телефонный код:
public void clientTest() {
int random = new Random().nextInt(1000);
Network network = Network.getInstance();
new Thread(network).start();
network.send(random + "");
network.close();
}
Это только для тестирования, в действительности потребности соединения оставаться открытым до тех пор, пока пользователь не закроет программу.
Вы вызываете send перед установкой 'out'. BTW Вам нужно сделать поле 'out' полем volatile, или вы никогда не увидите, что он установлен. –