TechnicalReport_01_04-Java Multithreading first view
TechnicalReport_01_04
1. Java MultiThreading
The following is the simplest multithreading code:
public class RyanAndMonicaTest{
public static void main(String[] args){
BankAccount account = new BankAccount();
RyanAndMonicaJob ryan = new RyanAndMonicaJob("Ryan", account, 50);
RyanAndMonicaJob monica = new RyanAndMonicaJob("Monica", account, 50);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(ryan);
executor.execute(monica);
executor.shutdown();
}
}
In the above the monica and ryan job will make change to variable of the instance BankAccount in the function of goShopping. So now we consider add a lock to instance BankAccount in the function go shopping specifing scope with curly bracket:
private void goShopping(int amount){
synchronized(account){
if(account.getBalance()>=amount){
System.out.println(name+" is about to spend");
account.spend(amount);
System.out.println(name+" finishes the transaction")
}
else{
System.out.println("Sorry, not enough for "+name);
}
}
}
Or we can lock the method goShopping() in the RyanAndMonicaJob class:
private synchronized void goShopping(int amount);
The above code has no effect, because the Ryan has RyanAndMonicaJob instance, the lock will lock on that instance, Monica has RyanAndMonicaJob instance, the lock will lock on that instance, two instance enter their own function seperately, not mutual exclusion.
The right solution is add synchronized in spend() in the BankAccount:
public synchronized void spend(String name, int amount){
if(balance>=amount){
balance = balance - amount;
System.Out.println(name+" spend money successfully.")
if(balance<0){
System.Out.println("Now, the remains is overdrawn.")
}
}
else{
System.Out.println("Sorry, remain is not enough for "+name);
}
}
The another method to achieve the multithreading is primitive. For example:
public synchronized increment(){
balance++;
}
or
Atomic variable:
class Balance{
AtomicInteger balance = new AtomicInteger(0);
public void increment(){
balance.incrementAndGet();
}
}
2. Another Example
- There is an example in the Singleton pattern implementation with multithreading:
public class Singleton{
private volatile static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance(){
if(uniqueInstance==null){
synchronized(Singleton.class){
if(uniqueInstance==null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
This is the DCL(Double-checked-locking) idea, use the volatile keyword , when the uniqueInstance has been created , other thread entering the line if(uniqueInstance==null) will see the uniqueInstance!=null.
volatile keyword is up to fix the problem that when some instructions instructing the code uniqueInstance = new Singleton(); will first create a reference to uniqueInstance, and then instruct initilization.
In fact, even if you do not have the first if(uniqueInstance==null), the code will also work, because the synchronized(Singleton.class) will ensure that the uniqueInstance will be created only once, but it will downside the performance, because every thread entering the getInstance() must wait for the lock on the Singleton.class.
3. CopyOnWriteArrayList
the is a safe data structure for multi threads reading and writing, especially for data that is read a lot, but not changed often.
public class ConcurrentReading{
public static void main(String[] args){
private List<Chat> ChatHistory = new CopyOnWriteArraylist<>;
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0;i<5;i++){
executor.execute(()->ChatHistory.add(new Chat("Hello!")));
executor.execute(()->System.out.println(ChatHistory));
executor.execute(()->System.out.println(ChatHistory));
}
executor.shutdown();
}
}
when some threads write to the array, they write to the copy of the array, meanwhile , the reading threads read the original array, and after the writing processes complete and update the original array with the copy, the threads executing reading will read the new array. And more than one thread writing will not affect the reading thread, reading thread will see the array snapshot in reading time. The many writing threads will block each other exclusively, executing:
- acquire the lock of the array
- make a copy of the array
- modify the array
- replace the array with the copy
- return the lock

浙公网安备 33010602011771号