how to make a callable implementing class multithread fast with parallel execution? - java

i am creating a class(CheckCon.java) that implements callable interface which basically returns the no. of devices Connected to the network. the problem is that i donot know how to execute it correctly because the results returned are really slow as compared to traditional multithreading. and i need to return values to a class in (NetScan.java). Kindly Help me execute it properly.
code for CheckCon.java (callable implementing class):
public class CheckCon implements Callable<Object>{
int startindex,endindex;
ArrayList<Object> list;
byte[] ip;
public CheckCon(int startindex, int endindex, byte[] ip) {
this.startindex = startindex;
this.endindex = endindex;
this.ip = ip;
list = new ArrayList<>();
}
#Override
public ArrayList<Object> call() throws Exception {
for(int i =startindex;i<endindex;i++){
try {
ip[3] = (byte)i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(1000))
{
System.out.println("Name is......"+address.getHostName()+"\tIP is......."+address.getHostAddress());
}
else if (!address.getHostAddress().equals(address.getHostName()))
{
String host = address.getCanonicalHostName();
String ipaddress =address.toString().replace(host+"/", "");
Object[] data = {host,ipaddress};
list.add(data);
System.out.println("Name is......"+address.getHostName()+"\tIP is......."+address.getHostAddress());
}
else
{
System.out.println("nothing");
// the host address and host name are equal, meaning the host name could not be resolved
} } catch (UnknownHostException ex) {
Logger.getLogger(NetScan.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(NetScan.class.getName()).log(Level.SEVERE, null, ex);
}
}
return list;
}
}
and the class Calling NetScan.java
private void getDataForTable() throws InterruptedException, ExecutionException {
ExecutorService executor =Executors.newCachedThreadPool();
for(int i =0; i<26 ; i++){
if(s == 250){
Future<Object> f =executor.submit(new CheckCon(s,s+5,ip));
list.add(f);
break;
}else{
Future<Object> f =executor.submit(new CheckCon(s,s+10,ip));
list.add(f);
s= s+10;
}
}
dm = new DefaultTableModel(ColumnName,0){
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
for(Future<Object> f : list){
dm.addRow((Object[]) f.get());
}}
I am creating 25 threads checking 10 IP's in each thread.

I removed the CheckCon.java and edited the NetScan to get what i Want thanks to #amit-bera . i Created a thread and asked the completablefuture to runasync with executor defining the no.of threads i require.
ExecutorService e =Executors.newFixedThreadPool(25);
for(int i =0;i<255;i++){
final int j =i;
f = CompletableFuture.runAsync(new Runnable() {
#Override
public void run() {
try {
ip[3] = (byte)j;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(1000))
{
System.out.println("Name is......"+address.getHostName()+"\tIP is......."+address.getHostAddress()+j);
}
else if (!address.getHostAddress().equals(address.getHostName()))
{
String host = address.getCanonicalHostName();
String ipaddress =address.toString().replace(host+"/", "");
Object[] data = {host,ipaddress};
dm.addRow(data);
System.out.println("Name is......"+address.getHostName()+"\tIP is......."+address.getHostAddress()+j);
}
else
{
System.out.println("nothing"+j);
// the host address and host name are equal, meaning the host name could not be resolved
} } catch (UnknownHostException ex) {
Logger.getLogger(NetScan.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(NetScan.class.getName()).log(Level.SEVERE, null, ex);
}
}
},e);
}
added this content to a method.

As per my obervationa please used singolton java pettern.example i am giving below.singolton alwaus retun instance so you save request response time on thread.
Thread is light-wight process but still initilised thread at whenever need.please make sure that thread work based on your server configrationa.
if you are using linux system
used TOP command to usage of your system perfomance and process execution on threadiwse.
i try and its work fine on my system.
class Singleton
{
private static Singleton single_instance = null;
public String s;
private Singleton()
{
s = "Hello I am a string part of Singleton class";
}
public static Singleton getInstance()
{
if (single_instance == null)
single_instance = new Singleton();
return single_instance;
}
}

Related

Jedis pool is initialised multiple times

I'm using redis with the help of jedis client. Attaching the code snippet for key value set/get here. Here I'm expecting my jedisPool to get initialised only once but it is getting initialised multiple times. Not sure where I'm going wrong. Scratching my head for several days with it. I have no clues why it does multiple initialisation.
//$Id$
package experiments.with.truth;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisClientUtil {
private static JedisPool pool; //I persume the deafult value initialised in my static variable would be null
static int maxActiveConnections = 8;
static int maxWaitInMillis = 2000;
static String host = "127.0.0.1";
static int port = 6379;
static int REDIS_DB = 1;
public static void initRedisClient() throws Exception {
try {
Class classObj = Class.forName("redis.clients.jedis.JedisPool");
if (classObj != null && pool == null) {
JedisPoolConfig jedisConfig = new JedisPoolConfig();
jedisConfig.setMaxTotal(maxActiveConnections);
jedisConfig.setMaxWaitMillis(maxWaitInMillis);
pool = new JedisPool(jedisConfig, host, port);
System.out.println("Pool initialised successfully !");
}
} catch(ClassNotFoundException ex) {
System.out.println("Couldn't initialize redis due to unavailability of jedis jar in your machine. Exception : " + ex);
}
}
public Jedis getJedisConnection() {
if(pool == null) {
initRedisClient();
}
return pool.getResource();
}
private static void returnJedis(Jedis jedis) {
try {
pool.returnResource(jedis);
} catch(Exception ex) {
ex.printStackTrace();
}
}
public static String getValue(String key) throws Exception{
Jedis jedisCon = null;
try {
jedisCon = getJedisConnection();
jedisCon.select(REDIS_DB);
String val = jedisCon.get(key);
return val;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedisCon != null) {
returnJedis(jedisCon);
}
}
return null;
}
public void addValueToRedis(String key, String value) {
Jedis jedisCon = null;
try {
jedisCon = getJedisConnection();
jedisCon.select(REDIS_DB);
jedisCon.set(key, value);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedisCon != null) {
returnJedis(jedisCon);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Value : " + getValue("a"));
System.out.println("Value : " + getValue("b"));
System.out.println("Value : " + getValue("c"));
}
}
I could see this debug log Pool initialised successfully multiple times when my program runs. Can someone help me find the loophole in this? Or how could I make this better (or make to behave it as expected) by initialising only once throughout the entire program.
Looks like a basic multithreading case. Your app asks for 5 connections in a short time. All of them see that pool==null and proceed initializing it.
Easy solution: public static synchronized void initRedisClient() throws Exception {
update and private static volatile JedisPool pool; otherwise you may get null pointer exception.
For more complex and performant solutions search 'efficient lazy singletor in java', which will most probably lead you to Enum solution.

Synchronized method() running only 1 thread till end from a poll of several

This is a project I'm trying to do for University.
I'm making an app using sockets to connect several Clients to a Server.
When I get a new connection a new instance of ServerHandler is called that listens to the port for requests from the Client.
This is my ServerHandler class
public class ServerHandler implements Runnable {
private Socket clientSocket;
private Server server;
ArrayList<Thread> threads = new ArrayList<Thread>();
ArrayList<News> news = new ArrayList<News>();
ArrayList<News> filteredNews = new ArrayList<>();
private int iterator = 0;
private boolean available = true;
private boolean finished = false;
public ServerHandler(Socket clientSocket, Server server) {
this.clientSocket = clientSocket;
this.server = server;
this.news = server.getListNews();
}
#Override
public void run() {
System.out.println("Hello!");
while(true) {
try {
System.out.println("Waiting for input");
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String str = br.readLine();
System.out.println(str);
new Thread(new Runnable() {
#Override
public void run() {
try {
manageMessages();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void manageMessages() throws IOException, InterruptedException {
System.out.println("Button Search.");
launchThreads(str);
for(Thread t : threads) {
t.join();
}
filteredNews.sort(null);
System.out.println("News have been filtered and sorted.");
System.out.println("Sending info to Client.");
sendtoClient();
System.out.println("Sent info to Client.");
}
}).start();
} catch (IOException e) {
System.out.println("Socket closed" + e);
break;
}
}
}
When I get a request I launch a new Thread responsible of returning something to the Client.
My problem comes from the launchThreads(String str) method.
This method is meant to create and add 10 threads to an Array of Threads.
Each Thread then is going to run through the same ArrayList of News in search of a word (String str, sent by the Client).
All threads are supposed to share the work, that is searching for the String str through every single News in the shared ArrayList<News>.
private void launchThreads(String str) {
System.out.println("Lauching threads");
filteredNews.clear();
threads.clear();
finished = false;
available = true;
iterator = 0;
for(int i = 0; i < 10; i++) {
threads.add(new Thread(new Runnable(){public void run(){try {
queueThreads(str);
filterNews(str);
} catch (InterruptedException e) {
e.printStackTrace();
}}}));
threads.get(i).start();
}
System.out.println("Launched threads: " + threads.size());
}
private synchronized void queueThreads(String str) throws InterruptedException {
while(!available && !finished) {
System.out.println("Waiting.");
wait();
}
System.out.println("Gone through.");
available = false;
}
private synchronized void filterNews(String str) throws InterruptedException {
int contador = 0;
if(iterator < news.size()) {
String temp = news.get(iterator).getTitle() + " " + news.get(iterator).getBody();
String[] tempArray = temp.replaceAll("[^a-zA-Z ]", "").split("\\s+");
for(String word : tempArray) {
if(word.equalsIgnoreCase(str)) {
contador++;
}
}
if(contador > 0) {
News n = new News(news.get(iterator).getTitle(),news.get(iterator).getBody(), contador);
n.setTitle(contador + " - " + n.getTitle());
System.out.println(news.get(iterator).toString());
filteredNews.add(n);
}
iterator++;
}else {
finished = true;
}
available = true;
notifyAll();
queueThreads(str);}
What I'm getting is that only 1 Thread runs the whole search while the other ones just stay waiting until I change the finished flag to 'true', that is set when the search ends.
I would love to get some help on how can I launch several threads to run through the array sharing work between them.
Thanks in advance.

Java how do I properly synchronize an arraylist over multiple threads?

I have a server that creates a thread for each client that connects to it. The main server class is called "Server" while each client is managed by a thread of a class "ClientManager" originating from Server. Server has a static arraylist of tiles (for a mahjong game) and when each client draws, the ClientManager removes that many tiles from the arraylist. I have the method that does this Synchronized (probably incorrectly), but when I run the program, it is as if the first player does not properly remove tiles from the list. When I look at my debug list it says "Player 1 draws, 144 tiles remain" when it should say 131. If I run the program in debug mode, it works perfectly fine. If I add Thread.sleep to the main method in Server that handles all of this, it works, but I don't like the incredibly long wait and would like to have the arraylists just synchronize properly and update properly. The first run should make the list go down by 13, then the next character draws 13 and so on. After that they would each draw 1, but the removing is not being reflected in the game.
Here is the relevant code from the client, server and client manager
Main:
public class Main {
static GamePanel gameGUI = new GamePanel();
static Client client;
static Player me = new Player();
//!!? is used to mark a username command
#SuppressWarnings("unchecked")
public static void main(String[] args) throws IOException{
String host = "107.199.245.55";
//String host = "107.199.244.144";
//String host = "localhost";
boolean created = false;
ArrayList<?> Temp = new ArrayList<Object>();
ArrayList<Tile> TileStack = new ArrayList<Tile>();
Object object = null;
int tiles = 0;
String username = "!!?" + JOptionPane.showInputDialog("Username:");
if(username.substring(3, username.length()).equals("null")){return;}
while(username.substring(3, username.length()).isEmpty()){
username = "!!?" + JOptionPane.showInputDialog("Must have an actual name\nUsername:");
}
int port = 27016;
//int port = 2626;
//int port = 4444;
client = new Client(host, port, username);
client.send(username);
gameGUI.initialize();
gameGUI.lblPlayerNameYou.setText(username.substring(3, username.length()));
waitForPlayers();
while(true)
{
try {
object = client.receive();
if(object instanceof ArrayList<?>)
{
Temp = (ArrayList<?>) object;
if(Temp.get(0) instanceof String)
{
setUpNames(username, Temp);
}
else if(Temp.get(0) instanceof Tile)
{
if(!created){
TileStack = (ArrayList<Tile>) Temp;
created = true;
for (int i = 0; i < 13; i++){me.drawOneTile(TileStack);}
client.send(13);
}
else if(created){
me.drawOneTile(TileStack);
client.send(1);
}
gameGUI.displayHand(me.hand);
}
}
else if(object instanceof Integer){
tiles = (int) object;
gameGUI.tilesRemaining.setText("Remaining Tiles: " + tiles);
}
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "You were disconnected. Exiting game.");
gameGUI.dispose();
break;
}
}
}
Server:
public class Server {
public static ArrayList<ObjectOutputStream> ConnectionArray = new ArrayList<ObjectOutputStream>();
public ArrayList<String> CurrentUsers = new ArrayList<String>();
public static ArrayList<Socket> ConnectionArraySOCKET = new ArrayList<Socket>();
public ArrayList<Tile> TileStack = new ArrayList<Tile>();
public static ServerGUI serverGUI;
public int port;
public ServerSocket SERVERSOCK;
public static GameLoop game = new GameLoop();
public static Server server;
public Server(int port){
this.port = port;
try {
SERVERSOCK = new ServerSocket(port);
} catch (IOException e) {
System.out.println("Unable to start");
e.printStackTrace();
}
serverGUI = new ServerGUI();
serverGUI.initialize();
}
public ArrayList<String> getCurrentUsers(){return CurrentUsers;}
public ArrayList<Tile> getTileStack(){return TileStack;}
public void waitForClients(ServerSocket SERVERSOCK)
{
serverGUI.addText(serverGUI.getDebugPane(), "Waiting for clients...");
while(ConnectionArray.size() < 4 && CurrentUsers.size() < 4)
{
try{
if (!(ConnectionArray.size() == 0)) shareToAll(ConnectionArray.size());
Socket client = SERVERSOCK.accept();
ConnectionArray.add(new ObjectOutputStream(client.getOutputStream()));
ConnectionArraySOCKET.add(client);
Thread t = new Thread(new ClientManager(client));
t.start();
if (!(ConnectionArray.size() == 0)) shareToAll(ConnectionArray.size());
}
catch(IOException e){e.printStackTrace();}
}
}
public static void shareToAll(Object o){
for(ObjectOutputStream stream : ConnectionArray)
{
try{
Thread.sleep(100);
stream.writeObject(o);
stream.reset();
stream.flush();
}
catch(Exception e){
e.printStackTrace();
}
}
}
public static void distributeTileStack(Object o, int playerNum){
try {
ConnectionArray.get(playerNum).writeObject(o);
ConnectionArray.get(playerNum).reset();
ConnectionArray.get(playerNum).flush();
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
public static boolean checkConnection()
{
if(ConnectionArray.size() < 4) return false;
else return true;
}
public static void main(String[] args) throws InterruptedException
{
server = new Server(Integer.parseInt(JOptionPane.showInputDialog("Port:")));
ArrayList<Tile> temp = new ArrayList<Tile>();
while(!serverGUI.started){
System.out.println("LOOP");
}
server.waitForClients(server.SERVERSOCK);
Server.shareToAll(server.getCurrentUsers());
game.createStack();
server.TileStack = game.getStack();
for (int i = 0; i <= 3; i++){
serverGUI.addText(serverGUI.getDebugPane(), "Player " + (i + 1) + " drawing tiles.");
temp = server.getTileStack();
Server.distributeTileStack(server.TileStack, i);
serverGUI.addText(serverGUI.getDebugPane(), "Tilestack size: " + server.getTileStack().size());
Server.shareToAll(server.getTileStack().size());
}
while(checkConnection()){
// game logic here
}
JOptionPane.showMessageDialog(null, "Player disconnected. The server will now close.");
serverGUI.btnStopServer.doClick();
serverGUI.dispose();
}
}
ClientManager:
public class ClientManager extends Thread implements Runnable {
Socket SOCK;
String username;
public ClientManager(Socket SOCK)
{
this.SOCK = SOCK;
}
public void run(){
boolean working = true;
try{
ObjectInputStream inStream = new ObjectInputStream(SOCK.getInputStream());
while(working){
working = handle(inStream);
}
}
catch(SocketException e){
e.printStackTrace();
System.out.println("Cannot get inputstream");
}
catch(IOException e){
e.printStackTrace();
}
}
public boolean handle(ObjectInputStream inStream){
Object object = null;
String string;
try{
object = inStream.readObject();
if(object instanceof String)
{
string = (String)object;
if(string.startsWith("!!?")){
username = string.substring(3, string.length());
synchronized (Server.class){
Server.server.CurrentUsers.add(username);
}
Server.serverGUI.addText(Server.serverGUI.getDebugPane(), "User connected: " + username + SOCK.getRemoteSocketAddress());
Server.serverGUI.addText(Server.serverGUI.getUsersPane(), username);
Server.serverGUI.addText(Server.serverGUI.getDebugPane(), "Number of users: " + Server.server.CurrentUsers.size());
}
}
if (object instanceof Integer)
{
synchronized(Server.class){
for (int i = 0; i < (int) object; i++)
Server.server.TileStack.remove(0);
}
}
}
catch(ClassNotFoundException ce){ce.printStackTrace();}
catch(IOException e){
e.printStackTrace();
for(int i = Server.ConnectionArray.size() - 1; i >= 0; i--)
{
if(Server.ConnectionArraySOCKET.get(i).equals(SOCK))
{
Server.serverGUI.addText(Server.serverGUI.getDebugPane(), "User " + Server.server.CurrentUsers.get(i) + SOCK.getRemoteSocketAddress() + " disconnected");
Server.serverGUI.clearText(Server.serverGUI.getUsersPane());
Server.server.CurrentUsers.remove(i);
Server.serverGUI.addText(Server.serverGUI.getDebugPane(), "Number of users: " + Server.server.CurrentUsers.size());
Server.ConnectionArraySOCKET.remove(i);
Server.ConnectionArray.remove(i);
for (int i2 = 1; i2 <= Server.server.CurrentUsers.size(); i2++){
Server.serverGUI.addText(Server.serverGUI.getUsersPane(), Server.server.CurrentUsers.get(i2-1));
}
if (!(Server.ConnectionArray.size() == 0)) Server.shareToAll(Server.ConnectionArray.size());
}
}
return false;
}
return true;
}
}
Create an interface whose implementation enforces a single instance of your list (singleton).
Example interface
interface SharedResource<T>{
public void add(T);
public T remove();
}
In it's implementation enforce a single instance
public List<Item> getInstance(){
if(myList == null){
myList = Collections.synchronizedList(TileStack);
}
return myList;
}
This way you can be sure each client is using the same list, this will eliminate each client having their own copy of a synchronized list.
Better Description
Or if you just want to make a class
public class MyResource{
List<Item> myList;
private MyResource(){}
public List<Item> getInstance(){
if(myList == null){
myList = Collections.synchronizedList(new ArrayList<Item>());
}
return myList;
}
}
You can simplify this as follows:
private ArrayDeque<Tile> tiles;
private ConcurrentHashMap<Integer, ArrayList<Tile>> preallocate;
private void preAllocate() {
for(int i = 0; i < 4; i++) {
ArrayList<Tile> temp = new ArrayList<>();
for(int j = 0; j < 13; j++) {
temp.add(tiles.pop());
}
preallocate.put(i, temp);
}
}
public ArrayList<Tile> get(int playerId) {
return preallocate.get(playerId);
}
You preallocate all of the players' hands in a single thread, so you don't need synchronization. You then use a thread-safe ConcurrentHashMap to store the players' hands so that again you don't need synchronization (the map takes care of that).
An alternative is to replace the ArrayList<tile> with a ConcurrentLinkedQueue<Tile>, where again you don't need to worry about synchronization because the data structure is handling it for you. Note however that this implementation would be "cheating" in that Player1 might not get the first 13 tiles, Player2 might not get the second 13 tiles, and so on - the tile allocation would be non-deterministic. However, I'm assuming that you're shuffling the tiles, in which case it shouldn't make any difference what order the players draw in. If this would be unacceptable then I'd recommend going with the preallocated ConcurrentHashMap (you could also accomplish this with the ConcurrentLinkedQueue, but it would be just as complicated as using a global ArrayList)

More conccurent users of Netty and BoneCP / Basic Socket Server

Disclaimer- I am not a Java programmer. Odds are I'll need to do my homework on any advice given, but I will gladly do so :)
That said, I wrote a complete database-backed socket server which is working just fine for my small tests, and now I'm getting ready for initial release. Since I do not know Java/Netty/BoneCP well- I have no idea if I made a fundamental mistake somewhere that will hurt my server before it even gets out the door.
For example, I have no idea what an executor group does exactly and what number I should use. Whether it's okay to implement BoneCP as a singleton, is it really necessary to have all those try/catch's for each database query? etc.
I've tried to reduce my entire server to a basic example which operates the same way as the real thing (I stripped this all in text, did not test in java itself, so excuse any syntax errors due to that).
The basic idea is that clients can connect, exchange messages with the server, disconnect other clients, and stay connected indefinitely until they choose or are forced to disconnect. (the client will send ping messages every minute to keep the connection alive)
The only major difference, besides untesting this example, is how the clientID is set (safely assume it is truly unique per connected client) and that there is some more business logic in checking of values etc.
Bottom line- can anything be done to improve this so it can handle the most concurrent users possible? Thanks!
//MAIN
public class MainServer {
public static void main(String[] args) {
EdgeController edgeController = new EdgeController();
edgeController.connect();
}
}
//EdgeController
public class EdgeController {
public void connect() throws Exception {
ServerBootstrap b = new ServerBootstrap();
ChannelFuture f;
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.localAddress(9100)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new EdgeInitializer(new DefaultEventExecutorGroup(10)));
// Start the server.
f = b.bind().sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally { //Not quite sure how to get here yet... but no matter
// Shut down all event loops to terminate all threads.
b.shutdown();
}
}
}
//EdgeInitializer
public class EdgeInitializer extends ChannelInitializer<SocketChannel> {
private EventExecutorGroup executorGroup;
public EdgeInitializer(EventExecutorGroup _executorGroup) {
executorGroup = _executorGroup;
}
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("idleStateHandler", new IdleStateHandler(200,0,0));
pipeline.addLast("idleStateEventHandler", new EdgeIdleHandler());
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.nulDelimiter()));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(this.executorGroup, "handler", new EdgeHandler());
}
}
//EdgeIdleHandler
public class EdgeIdleHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger( EdgeIdleHandler.class.getName());
#Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception{
if(evt instanceof IdleStateEvent) {
ctx.close();
}
}
private void trace(String msg) {
logger.log(Level.INFO, msg);
}
}
//DBController
public enum DBController {
INSTANCE;
private BoneCP connectionPool = null;
private BoneCPConfig connectionPoolConfig = null;
public boolean setupPool() {
boolean ret = true;
try {
Class.forName("com.mysql.jdbc.Driver");
connectionPoolConfig = new BoneCPConfig();
connectionPoolConfig.setJdbcUrl("jdbc:mysql://" + DB_HOST + ":" + DB_PORT + "/" + DB_NAME);
connectionPoolConfig.setUsername(DB_USER);
connectionPoolConfig.setPassword(DB_PASS);
try {
connectionPool = new BoneCP(connectionPoolConfig);
} catch(SQLException ex) {
ret = false;
}
} catch(ClassNotFoundException ex) {
ret = false;
}
return(ret);
}
public Connection getConnection() {
Connection ret;
try {
ret = connectionPool.getConnection();
} catch(SQLException ex) {
ret = null;
}
return(ret);
}
}
//EdgeHandler
public class EdgeHandler extends ChannelInboundMessageHandlerAdapter<String> {
private final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
private long clientID;
static final ChannelGroup channels = new DefaultChannelGroup();
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Connection dbConnection = null;
Statement statement = null;
ResultSet resultSet = null;
String query;
Boolean okToPlay = false;
//Check if status for ID #1 is true
try {
query = "SELECT `Status` FROM `ServerTable` WHERE `ID` = 1";
dbConnection = DBController.INSTANCE.getConnection();
statement = dbConnection.createStatement();
resultSet = statement.executeQuery(query);
if (resultSet.first()) {
if (resultSet.getInt("Status") > 0) {
okToPlay = true;
}
}
} catch (SQLException ex) {
okToPlay = false;
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException logOrIgnore) {
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException logOrIgnore) {
}
}
if (dbConnection != null) {
try {
dbConnection.close();
} catch (SQLException logOrIgnore) {
}
}
}
if (okToPlay) {
//clientID = setClientID();
sendCommand(ctx, "HELLO", "WORLD");
} else {
sendErrorAndClose(ctx, "CLOSED");
}
}
#Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
channels.remove(ctx.channel());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, String request) throws Exception {
// Generate and write a response.
String[] segments_whitespace;
String command, command_args;
if (request.length() > 0) {
segments_whitespace = request.split("\\s+");
if (segments_whitespace.length > 1) {
command = segments_whitespace[0];
command_args = segments_whitespace[1];
if (command.length() > 0 && command_args.length() > 0) {
switch (command) {
case "HOWDY": processHowdy(ctx, command_args); break;
default: break;
}
}
}
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
TraceUtils.severe("Unexpected exception from downstream - " + cause.toString());
ctx.close();
}
/* */
/* STATES - / CLIENT SETUP */
/* */
private void processHowdy(ChannelHandlerContext ctx, String howdyTo) {
Connection dbConnection = null;
Statement statement = null;
ResultSet resultSet = null;
String replyBack = null;
try {
dbConnection = DBController.INSTANCE.getConnection();
statement = dbConnection.createStatement();
resultSet = statement.executeQuery("SELECT `to` FROM `ServerTable` WHERE `To`='" + howdyTo + "'");
if (resultSet.first()) {
replyBack = "you!";
}
} catch (SQLException ex) {
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException logOrIgnore) {
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException logOrIgnore) {
}
}
if (dbConnection != null) {
try {
dbConnection.close();
} catch (SQLException logOrIgnore) {
}
}
}
if (replyBack != null) {
sendCommand(ctx, "HOWDY", replyBack);
} else {
sendErrorAndClose(ctx, "ERROR");
}
}
private boolean closePeer(ChannelHandlerContext ctx, long peerClientID) {
boolean success = false;
ChannelFuture future;
for (Channel c : channels) {
if (c != ctx.channel()) {
if (c.pipeline().get(EdgeHandler.class).receiveClose(c, peerClientID)) {
success = true;
break;
}
}
}
return (success);
}
public boolean receiveClose(Channel thisChannel, long remoteClientID) {
ChannelFuture future;
boolean didclose = false;
long thisClientID = (clientID == null ? 0 : clientID);
if (remoteClientID == thisClientID) {
future = thisChannel.write("CLOSED BY PEER" + '\n');
future.addListener(ChannelFutureListener.CLOSE);
didclose = true;
}
return (didclose);
}
private ChannelFuture sendCommand(ChannelHandlerContext ctx, String cmd, String outgoingCommandArgs) {
return (ctx.write(cmd + " " + outgoingCommandArgs + '\n'));
}
private ChannelFuture sendErrorAndClose(ChannelHandlerContext ctx, String error_args) {
ChannelFuture future = sendCommand(ctx, "ERROR", error_args);
future.addListener(ChannelFutureListener.CLOSE);
return (future);
}
}
When a network message arrive at server, it will be decoded and will release a messageReceived event.
If you look at your pipeline, last added thing to pipeline is executor. Because of that executor will receive what has been decoded and will release the messageReceived event.
Executors are processor of events, server will tell which events happening through them. So how executors are being used is an important subject. If there is only one executor and because of that, all clients using this same executor, there will be a queue for usage of this same executor.
When there are many executors, processing time of events will decrease, because there will not be any waiting for free executors.
In your code
new DefaultEventExecutorGroup(10)
means this ServerBootstrap will use only 10 executors at all its lifetime.
While initializing new channels, same executor group being used:
pipeline.addLast(this.executorGroup, "handler", new EdgeHandler());
So each new client channel will use same executor group (10 executor threads).
That is efficient and enough if 10 threads are able to process incoming events properly. But if we can see messages are being decoded/encoded but not handled as events quickly, that means there is need to increase amount of them.
We can increase number of executors from 10 to 100 like that:
new DefaultEventExecutorGroup(100)
So that will process event queue faster if there is enough CPU power.
What should not be done is creating new executor for each new channel:
pipeline.addLast(new DefaultEventExecutorGroup(10), "handler", new EdgeHandler());
Above line is creating a new executor group for each new channel, that will slow down things greatly, for example if there are 3000 clients, there will be 3000 executorgroups(threads). That is removing main advantage of NIO, ability to use with low thread amounts.
Instead of creating 1 executor for each channel, we can create 3000 executors at startup and at least they will not be deleted and created each time a client connects/disconnects.
.childHandler(new EdgeInitializer(new DefaultEventExecutorGroup(3000)));
Above line is more acceptable than creating 1 executor for each client, because all clients are connected to same ExecutorGroup and when a client disconnects Executors still there even if client data is removed.
If we must speak about database requests, some database queries can take long time to being completed, so if there are 10 executorss and there are 10 jobs being processed, 11th job will have to wait until one of others complete. This is a bottleneck if server receiving more than 10 very time consuming database job at the same time. Increasing count of executors will solve bottleneck to some degree.

How to synchronize my port scanner so results would appear in order in which they were executed?

I created a class which will try to scan ports of certain host.
The problem is that I get result in a random fashion or w/e finishes first.
How would I make sure that results will display in order I execute this port scan?
Test method (sorry Google):
public class SimplePortScanner
{
public static void main(String[] args)
{
for(int i = 78; i < 85; i++)
{
new Scanner("google.com", i).start();
}
}
}
Port scan method:
import java.net.*;
public class Scanner extends Thread
{
private String address;
private int port;
Scanner(String address, int port)
{
super(address);
this.address = address;
this.port = port;
}
public void run()
{
try
{
SocketAddress sa = new InetSocketAddress(address, port);
Socket socket = new Socket();
socket.connect(sa, 2000);
System.out.println("Port in use: " + port);
socket.close();
}
catch (Exception e)
{
System.out.println("Port not in use: " + port);
}
}
}
I was thinking of creating a thread number and save results in array in order they were executed (at least how I see it in my mind).
How to do this correctly? I'm just messing around with threading so sorry if I'm messing something up here...
Try java.util.concurrent
class Scanner implements Callable<Boolean> {
....
#Override
public Boolean call() {
try {
....
return true;
} catch(Exception e) {
return false;
}
}
}
ExecutorService ex = Executors.newCachedThreadPool();
List<Scanner> tasks = new ArrayList<>();
for (int i = 78; i < 85; i++) {
tasks.add(new Scanner("google.com", i));
}
List<Future<Boolean>> list = ex.invokeAll(tasks);
for(int i = 0; i < tasks.size(); i++) {
if (list.get(i).get()) {
System.out.printf("Port is in use: %d", tasks.get(i).port());
} else {
System.out.printf("Port is not in use: %d", tasks.get(i).port());
}
}
// dont forget to shutdown executor
ex.shutdown();

Categories

Resources