Console Based Application Doesn't Show Suggestions - java

I am working on a console based Java application. I've to show suggestions to user for selecting a database. I am using Scanner for reading input and a separate thread for checking if input contains TAB in order to print the suggestions.
UPDATE
As per below answer, I added synchronized block to code and the Exception is gone. However, I don't see any suggestions printed on the console. Below is my current code:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class Test {
private static List<String> suggestions = new ArrayList<>();
private static final Object lock = new Object();
public static void main(String[] arguments) {
suggestions.add("H2");
suggestions.add("Mongo");
suggestions.add("MySQL");
suggestions.add("Oracle");
suggestions.add("PostgreSQL");
suggestions.add("SQLite");
Scanner scanner = new Scanner(System.in);
System.out.println("Enter a database name, press TAB for suggestions");
new Thread(new Runnable() {
public void run() {
while (true) {
synchronized (lock) {
if (scanner.hasNext()) {
String input = scanner.next();
if (input.contains("\\t")) {
System.out.println(getSuggestions(input));
}
}
}
}
}
}).start();
synchronized (lock) {
String selectedDatabase = scanner.nextLine();
System.out.println(selectedDatabase);
}
}
private static List<String> getSuggestions(String input) {
List<String> possibleSuggestions = new ArrayList<>();
for (String suggestion : suggestions) {
if (suggestion.startsWith(input)) {
possibleSuggestions.add(suggestion);
}
}
return possibleSuggestions;
}
}
Could somebody please help?

Simply put, Scanner is not a thread-safe class and you are using it in two different threads.
You instantiate the scanner it in the Main thread and use it in the other one. In the background the constructor of Scanner might have initialized fields that are not necessarily synced to the other thread.
And while the other thread runs you do a scanner.nextLine() in the Main thread which might execute at the exact same time as the other thread doing a scanner.hasNext(), leading to concurrent access.
You need a way to synchronize access to the scanner (everywhere), e.g. by means of a lock.
synchronized (lock) {
if (scanner.hasNext()) {
String input = scanner.next();
if (input.contains("\\t")) {
System.out.println("ok");
}
}
}
where the lock is a static field you synchronize on:
private static final Object lock = new Object();

Related

using Scanner and next() with println error

import java.util.Scanner;
import static java.lang.Thread.sleep;
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name){
threadName = name;
}
public void run() {
System.out.println("asd");
}
public void start ()
{
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
class RunnableDemo1 implements Runnable {
private Thread t;
private String threadName;
RunnableDemo1( String name){
threadName = name;
}
public void run() {
Scanner in = new Scanner(System.in);
System.out.print("Enter here:");
String x = in.nextLine();
System.out.println(x);
}
public void start ()
{
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
RunnableDemo1 R1 = new RunnableDemo1( "Thread-1");
R1.start();
sleep(1000);
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
Println will print a line to the command prompt but in.nexLine() (also tried in.next() does not recognize it. Is there any way I am able to print a string to the command prompt and have the scanner recognize it? Or something similar?
System.out.println shouldn't send anything to the server since it sends the String to the standard out only, usually the console, unless you've re-routed the standard out, something that I don't recommend that you do. Instead you need to actually send something to the server, perhaps in your notifyObservers method, but hard to say without your mcve.
In all this remains a very incomplete question until you improve it.
Edit: yes the Observable API shows that public void notifyObservers(Object arg) has an overload that accepts an Object parameter. Why not pass your String in there?
Edit 2: OK, you're confused, because that's not how you have one class communicate with another. Printing something out to the console will not trigger the System.in to update in another thread. Again, do what I stated above.

Calling variables from other class

import java.util.Scanner;
public class ThreadClass{
public static void main(String[] args)
{
System.out.println("Enter the characters, Press Enter to begin");
System.out.println("The quick brown fox jumps over the lazy dog");
Scanner sc=new Scanner(System.in);
String scr= sc.nextLine();
MyThread tr=new MyThread();
try {
tr.sleep(11000);
System.out.println("Time Over");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class MyThread extends Thread{
public void run()
{
System.out.println("Time over");
ThreadClass tc=new ThreadClass();
String str=tc.scr;
if(str.equals("The quick brown fox jumps over the lazy dog"))
{
System.out.println("Successfully completed");
}
else
{
System.out.println("The typed Words do not match");
}
}
}
I am trying to make an application that prompts the user to type a string within 11 seconds. To accomplish this I have two classes namely ThreadClass and MyThread. In Thread class I have defined methods to take input from the user and to set the timer to 10 seconds. In MyThread class I have defined methods for post thread completion i.e. what the program will do after the time is over. I want to add a feature in MyThread class so that it compares the user input with the string provided. The problem is that when I try to access the String variable scr, defined in ThreadClass from MyThread class by creating an it gives me an error. Even if I try to extend ThreadClass from MyThread class it gives me an error. Also declaring scr as static gives me the same result. Is there any possible way to use scr variable in MyThread?
I had while ago same issue, i used Concurrency API from java, and it works without problem
here is solution for your problem
public class ThreadClass {
public static void main(String[] args) {
final ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
System.out
.println("Enter the characters, Press Enter to begin");
System.out
.println("The quick brown fox jumps over the lazy dog");
Scanner sc = new Scanner(System.in);
return sc.nextLine();
}
});
try {
String str = future.get(11, TimeUnit.SECONDS);
System.out.println("Your string " + str);
} catch (TimeoutException | InterruptedException | ExecutionException e) {
future.cancel(true);
System.out.println("Time Over");
}
}
}
You didn't tell us what the error message is, but I can guess.
ThreadClass tc=new ThreadClass();
String str=tc.scr;
There is no instance variable named scr in your ThreadClass class. There is only a local variable with that name in your main() routine.
If you do not yet understand the difference between local variables, instance variables (a.k.a., "fields") and class variables (a.k.a., "static variables"), then it might be a little bit early for you to be trying to understand threads.

Lock objects for all threads?

I have this small sample of code, while modifying the list, i lock it with synchronized, but while reading the list it comes to ConcurrentModificationException, because without "synchronized" the lock has no effect. Is it possible to lock an object for all threads which use the object, even the un-synchronized, too?
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Test {
public static void main(String[] args) {
final Random r = new Random(System.currentTimeMillis());
List<Integer> list = new ArrayList<>();
new Thread(new Runnable() {
public void run() {
while (true) {
synchronized (list) {
list.add(r.nextInt());
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
for (Integer i : list) {
System.out.println(i);
}
}
}
}).start();
}
}
the backgorund is that i dont want to change all pieces in my code which read the object
You might consider using a concurrent implementation of List, instead of ArrayList. Perhaps a CopyOnWriteArrayList.
final List<Integer> list = new CopyOnWriteArrayList<Integer>();
Is it possible to lock an object for all threads which use the object.
In a word, No. When one thread enters a synchronized(foo) {...} block, that does not prevent other threads from accessing or modifying foo. The only thing it prevents is, it prevents other threads from synchronizing on the same object at the same time.
What you can do, is you can create your own class that encapsulates both the lock and the data that the lock protects.
class MyLockedList {
private final Object lock = new Object();
private final List<Integer> theList = new ArrayList<>();
void add(int i) {
synchronized(lock) {
theList.add(i);
}
}
void printAll() {
synchronized(lock) {
for (Integer i : theList) {
System.out.println(... i ...);
}
}
}
...
}
If you can modify the function which concurrently uses the object, just add synchronized in every critical section:
while (true) {
synchronized(list){
for (Integer i : list) {
System.out.println(i);
}
}
}
if you can't , create a specified lock that is responsible for locking the threads:
Lock lock = new Lock();
new Thread(new Runnable(){
//...
synchronized(lock){
do unsynchonized function on list
}
//...
}).start();
new Thread(new Runnable(){
//...
synchronized(lock){
do unsynchonized function on list
}
//...
}).start();
the latter may slow down the process if one of the functions already doing some locking, but in this way you can ensure you always synchronize the access to concurrent objects.

Java - Synchronized

Hi i have made a something that extends thread that adds adds an object that has a IP in it. then i made two instances of this thread and started them. they use the same list.
I now want to use Synchronized to stop the concurrent update problem. But its not working and i cant work out why.
My main class:
import java.util.*;
import java.io.*;
import java.net.*;
class ListTest2 {
public static LinkedList<Peer> myList = new LinkedList<Peer>();
public static void main(String [] args) {
try {
AddIp test1 = new AddIp(myList);
AddIp test2 = new AddIp(myList);
test1.start();
test2.start();
} catch(Exception e) {
System.out.println("not working");
}
}
}
My thread class:
class AddIp extends Thread {
public static int startIp = 0;
List<Peer> myList;
public AddIp(List<Peer> l) {
myList = l;
}
public synchronized void run() {
try {
startIp = startIp+50;
int ip = startIp;
InetAddress address = InetAddress.getByName("127.0.0.0");
Peer peer = new Peer(address);
while(ip <startIp+50) {
ip++;
address = InetAddress.getByName("127.0.0."+ip);
peer = new Peer(address);
myList.add(peer);
if(myList.indexOf(peer)== (myList.size() -1)) {
} else {
System.out.println("Lost"+peer.peerIp);
}
}
} catch(Exception e) {
}
}
}
Can anyone help me out here im lost for ideas thanks.
public synchronized void run()
Synchronizes on calling instance: this.
So,
1st thread synchronizes on test1 and 2nd thread synchronizes on test2, which doesn't help at all.
You want to synchronize on the shared resource, in this case: myList
public void run() {
synchronize(myList){
//your Logic
}
}
As a side note: Implement runnable instead of extending a Thread. Read more here.
You'd be better off implementing Runnable oppose to extending thread
also
public void run() {
synchronize(list){
//stuffs
}
}
they use the same list.
You can try to use Vector instead List. Vector is synchronized
or set your List to be synchronized:
List myList = Collections.synchronizedList(myList);
instead to use:
synchronize(myList){
}
The easiest way is to use a List implementation that can handle multiple threads. Try CopyOnWriteArrayList.

How to update immediately shared variables between threads

My test program asks for a string and prints it every 2 seconds. I've read some already about java memory model or how threads don't immediately update their variables on the main memory.
I've tried with volatile and static attributes. Synchronizing code blocks in which the variable line was modified. With wait()/notifi() when the variable was changed and some others. How do I assign line as a reference and not as value? Am I using the methods I tried wrong? Why can objects stay perfectly synchronized when they act as monitors but they can't be when acting as pointers?
public class TestSharedVariable {
static String line= "";
public static void main(String[] args) {
// For reading from keyboard
Scanner keyboard = new Scanner(System.in);
Printer p = new Printer(line);
p.start();
// Reads a line from keyboard into the shared variable
while(!line.equals("quit")){
line = keyboard.nextLine();
}
}
}
class Printer extends Thread{
private volatile String line;
public Printer(String palabra){
this.line = palabra;
}
/* Prints the line each 2 sec */
#Override
public void run(){
while(!line.equals("quit")){
try {
sleep(2000);
} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(this.getName() + ": " + line);
}
}
}
Output:
Thread-0:
asdf
Thread-0:
Thread-0:
You have two main issues:
For one Strings are immutable, and so you cannot change the state of a String variable, such as the characters that comprise it, once it has been created, and
You are assigning two reference variables to the same object, but are expecting one variable to change its assignment if the other variable's assignment changes, and this isn't how Java reference variables work.
In other words, even though you're initially setting the Printer object's line variable to the same reference as the TestSharedVariable's static line variable, changing the TestSharedVariable's static line variable's reference later will have no effect on Printer line variable's reference assignment. This has nothing to do with threading and all to do with understanding reference variables. Think of reference variables like pointers in C or other similar languages. If two variables point to the same object, changing one variable to point to a different object will have no effect on the first variable.
For your code to work, both variables must share a reference to the same mutable object, and you must change the state of the mutable object, not the reference to it.
For e.g.,
import java.util.Scanner;
public class TestSharedVariable {
static volatile MutableObject mutableObject = new MutableObject();
public static void main(String[] args) {
// For reading from keyboard
Scanner keyboard = new Scanner(System.in);
Printer p = new Printer(mutableObject);
new Thread(p, "Print thread").start();
// Reads a line from keyboard into the shared variable
while (!mutableObject.getData().equals("quit")) {
mutableObject.setData(keyboard.nextLine());
}
}
}
class Printer implements Runnable {
private volatile MutableObject mutableObject;
public Printer(MutableObject mutableObject) {
this.mutableObject = mutableObject;
}
/* Prints the line each 2 sec */
#Override
public void run() {
while (!mutableObject.getData().equals("quit")) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + ": " + mutableObject);
}
}
}
class MutableObject {
private String data = "";
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#Override
public String toString() {
return data;
}
}

Categories