THREAD IN JAVA
MULTITHREADING
Multithreading is the simultaneous execution (real or virtual) of multiple threads belonging to the same process. Multithreading can be:
- Collaborative: threads remain active until they finish the task or cede control of occupied resources.
- Preventive: the virtual machine can access an active thread and control it through another thread
The Java Language Specification states that the VM should manage threads according to preemptive scheduling (fixed-priority scheduling).
Each execution of the VM corresponds to one process. Everything that is executed by the VM corresponds to a thread.
Each thread is concerned with solving a particular problem. By performing the operations in parallel, the final result can be achieved more quickly. In multi-threaded software, threads can exchange information and access shared resources.
Example
We need to develop a chat that works like this:
- The chat server remains listening for messages arriving on a port
- for each new user connected, a thread is created that is responsible for capturing messages sent by the user and forwarding them to other connected users In this case we will have a thread for each connected user. Let’s look at a simple example of multithreading.
This is the main method.
CONCURRENCY IN JAVA
Concurrency is the ability to run different parts (multiple tasks) of a program in parallel. Today, with devices equipped with several CPUs or multicore, it is possible to parallelize processes. Parallelization makes it possible to:
- make the best use of the hardware
- reduce processing time
- Improve the execution of software
In java, you can implement concurrency through three tools:
- The Threads: these were the first tools made available (they were present in version 1.0), the ones we will use in our example.
- The Executor framework, introduced since version 1.5.
- The Fork/Join framework, starting with version 1.7.
Using Threads
To create a Thread you need to create a class that extends the Thread class or implements Runnable and implements the run() method. To start the thread, you must invoke the start() method and wait for the join() method to complete the task. The run() method has no input parameters and does not return values, so in order to pass parameters to the thread, it is possible to define a custom constructor of our class that receives the necessary parameters as input.
Let’s look at the code for the main method.
I think it is useful not to address the other two methods but to move immediately to synchronization between Threads, a very important topic.
SYNCHRONIZATION
What happens if two Threads access the same instance of a class and invoke methods? What happens if by invoking a method we change the state of the object?
Example
Suppose Mario and Lucia are contestants of a bank account. Mario and Lucia can access the same account. What happens if Mario and Lucia view the bank statement and withdraw from two different ATMs at the same time? Theoretically, Mario and Lucia think there is enough money in the account, but it is not certain. Double withdrawal could lead to a negative account value. In the above example, Mario and Lucia are two different threads accessing the same resource: the bank account. To handle situations where multiple threads are accessing the same resource, it is necessary to use appropriate synchronization mechanisms.
THE KEYWORD SYNCHRONIZED
The JVM supports synchronization via the keyword synchronized. In Java, it is possible for a thread to maintain exclusive access on a resource. In this way, no other thread can access it until the resource is made available by the thread that blocked it.
package it.corso.java.syncronized; public class Cliente extends Thread { public static void main(String[] args)throws InterruptedException{ Cliente c1 = new Cliente("Mario", 1200); Cliente c2 = new Cliente("Lucia", 50); // Avvio i Threads c1.start(); c2.start(); // Attendo il completamento c1.join(); c2.join(); } private double sommaDaPrelevare; public Cliente(String nomeCliente, double sommaDaPrelevare) { super(); this.setName(nomeCliente); this.sommaDaPrelevare = sommaDaPrelevare; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " arriva al bancomat"); System.out.println("Quando arriva " + Thread.currentThread().getName() + " il saldo è: " + ContoCorrente.getInstance().getSaldo()); System.out.println("La somma che vuole prelevare " + Thread.currentThread().getName() + " : " + sommaDaPrelevare); try { ContoCorrente.getInstance().prelievo(sommaDaPrelevare); System.out.println(Thread.currentThread().getName() + " TUTTO OK PRELIEVO EFFETTUATO"); } catch (Exception e) { System.out.println(Thread.currentThread().getName() + "NON HAI SOLDI!!!"); String a = e.getMessage(); System.out.println(a); } } }
package it.corso.java.syncronized; import java.io.*; public class ContoCorrente { private static ContoCorrente cc; public static ContoCorrente getInstance() { if(cc == null) cc = new ContoCorrente(); return cc; } public double getSaldo() { double saldo = 0; BufferedReader br = null; try { File fin = new File(new File(".").getCanonicalPath() + File.separator + "db.txt"); br = new BufferedReader(new FileReader(fin)); String line = null; while ((line = br.readLine()) != null) { saldo = Double.parseDouble(line); break; } } catch (IOException e) { e.printStackTrace(); } finally { if(br != null) try { br.close(); } catch (IOException e) { e.printStackTrace(); } } return saldo; } public synchronized void prelievo(double somma) throws Exception { Thread.sleep(5000); BufferedWriter bw = null; FileWriter fw = null; try { double nuovoSaldo = getSaldo() - somma; if(nuovoSaldo > 0) { fw = new FileWriter(new File(".").getCanonicalPath() + File.separator + "db.txt"); bw = new BufferedWriter(fw); bw.write(nuovoSaldo+""); } else throw new Exception("Saldo insufficiente!"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bw != null) bw.close(); if (fw != null) fw.close(); } catch (IOException ex) { ex.printStackTrace(); } } } }
LINKS TO PREVIOUS POSTS
LINK TO CODE ON GITHUB
EXECUTION OF THE EXAMPLE CODE
- Download the code from GITHUB, launch the JAR file with the following command in Visual Studio Code, locating in the directory containing the JAR.
java -jar –enable-preview CorsoJava.jar
- Or run the main found in the file CorsoJava.java.
Leave A Comment