Java @ Desk: Threads | Java at your desk

Restart Threads in Java using UncaughtExceptionHandler

Restart Threads in Java using UncaughtExceptionHandler

A lot of interview rooms listen to this question and a lot of candidates stop on a "No". Hope you have an elaborate answer after reading this post.

Threads have always been the most debated, misunderstood and under estimated component in Java. What makes this component even more mysterious is its ability to be controlled by the OS Scheduler of your underlying operating system. Threads are something that makes your code OS dependent and take away the ability of it to be "PLATFORM INDEPENDENT".

A very common interview question is can they be restarted. If you are handling the instantiation of your Thread,it cannot be restarted if it has finished its execution (terminated state). Done so, it throws a java.lang.IllegalThreadStateException exception.

public class ThreadState extends Thread {
 
 public void run(){
  System.out.println("I am in Run");
 }

 public static void main(String[] args) throws Exception{
  ThreadState threadState = new ThreadState();
  threadState.start();
  System.out.println(threadState.getStackTrace());
  Thread.sleep(100);
  
  System.out.println(threadState.getStackTrace());
  threadState.start();
  System.out.println(threadState.getStackTrace());
  
 }
}


Another direction this question could be answered is Thread Pools. You do not atomically handle thread starts when using Thread Pools. That logic is implemented by the thread Pool. Neither does the thread of a pool go to TERMINATED state when finished executing, it goes back to the pool and is made available for other tasks.

To add more to it, Threads cannot be exactly restarted but you can instantiate a new object of Thread and do so on your thread terminating condition. Most common reason threads can terminate is because of Exceptions. This can be achieved using UncaughtExceptionHandler Interface. It was introduced in Java 1.5 version.

Your interviewer might want an answer to a scenario which I quote now:
Let’s say you have a polling application which polls to check if an integer has a specific value. If you reach that specific value, your next task can start executing. You will have to keep re-polling until integer reaches that specific state. Below is the implementation:
class CustomExceptionhandler implements UncaughtExceptionHandler{

 public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
  System.out.println("I have reached the Re Instantiation Of Thread");
  new PollingThread().start();
  System.out.println("Re Instantiation Of Thread completed and Thread started"); 
 } 
}


public class PollingThread extends Thread {
 
 public void run(){
  this.setUncaughtExceptionHandler(new CustomExceptionhandler());
  int randomIntvalue = new Random().nextInt(5) ;
  if(randomIntvalue > 3){
   System.out.println("Polling successfull...Int value = "+randomIntvalue);
   System.out.println("Polling state achieved");
  }else{
   System.out.println("Polling un- successfull...Int value = "+randomIntvalue);
   System.out.println("Application needs to Repoll");
   intdivideByZero = 1/0;
  }
 }
 
 public static void main(String[] args){
  System.out.println("I am starting to Poll now");
  new PollingThread().start();
 }
}


setUncaughtExceptionHandler() method sets the objects of concrete UncaughtExceptionHandler type on your Thread. uncaughtException method is invoked every time an exception occurs in your Thread Execution. I have re-instantiated my Thread and started it in this method. Note , I have re-instantiated my Thread and not restarted it. So Threads cannot be restarted but they can surely be re-instantiated at thread terminating condition.



The above application could go out of memory if the randomIntvalue variable never achieves its desired value. Or in logical terms, the poll never gets over. So this thought could also be presented with a ThreadPool. I have built a Thread Pool of capacity 10 using java.util.concurrent.ExecutorService. If the thread does not have an explicit uncaught exception handler set, and the thread's thread group (including parent thread groups) does not specialize its uncaughtException method, then the default handler'suncaughtExceptionmethod will be invoked.By setting the default uncaught exception handler, an applicationcan change the way in which uncaught exceptions are handled (such as logging to a specific device, or file) for those threads that wouldalready accept whatever behavior the system provided.

class CustomExceptionHandler implements UncaughtExceptionHandler{

 public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
  System.out.println("I have reached the Re Instantiation Of Thread");
  PollingThread.submitThreadToPool(new PollingThread());
  System.out.println("Re Instantiation Of Thread completed and Thread started");
 }
}

public class PollingThread extends Thread {
 
 static ExecutorService executorService = Executors.newFixedThreadPool(10);
 
 public void run(){
  this.setUncaughtExceptionHandler(new CustomExceptionHandler());
  int randomIntvalue = new Random().nextInt(5) ;
  if(randomIntvalue > 3){
   System.out.println("Polling successfull...Int value = "+randomIntvalue);
   System.out.println("Polling state achieved");
   getThreadPool().shutdown();
  }else{
   System.out.println("Polling un- successfull...Int value = "+randomIntvalue);
   System.out.println("Application needs to Repoll");
   intdivideByZero = 1/0;
  }
 }
 
 public static void main(String[] args){
  Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler());
  System.out.println("I am starting to Poll now");
  executorService.execute(new PollingThread());
 }
 
 public static void submitThreadToPool(Runnable runnable){
  executorService.execute(runnable);
 }
 
 public static ExecutorService getThreadPool(){
  returnexecutorService;
  
 }

}


This post is written by
Komal Ahluwalia - Linkedin, Google Plus
She is a freelance writer, loves to explore latest features in Java technology.


SynchronousQueue Example in Java - Producer Consumer Model

SynchronousQueue Example in Java - Producer Consumer Model

In one of our previous posts, we learnt Producer Consumer in Java using BlockingQueue and Producer Consumer Using PriorityBlockingQueue where the main characteristic of a Producer and Consumer was it comes up with the size of the queue.

In above implementation, the queue gets initialized with the size attribute. The size attribute of the queue makes sure "Producer put an element in the queue only if the current size of the queue < Size Attribute defined while initialization".

For example, if the queue is initialized as :
BlockingQueue<ProducerConsumerBean> blockingQueue = new ArrayBlockingQueue<ProducerConsumerBean>(10);

then,
if(blockingQueue.size() == 10)
, put() enters into wait state. Once consumer starts taking the element out using take() method (blockingQueue.take()), it notifies the producer to producer to put further elements. In above example, Max elements the producer can put before entering in WAIT state is 10.
As stated, put() and take() methods run independently unless the size reaches 0 or Maximum.

On the other hand, SynchronousQueue works in a similar fashion with following major differences:
1) The size of SynchronousQueue is 0
2) put() method will only insert an element if take() method will be able to fetch that element from the queue at the same moment i.e. an element cannot be inserted if the consumer take() call is going to take some time to consume it.

SynchronousQueue - Insert only when someone will recieve it at that moment itself.

ProducerConsumerBean.java
package com.synchronousqueue;

public class ProducerConsumerBean {

 private String emailId;

 public String getEmailId() {
  return emailId;
 }

 public void setEmailId(String emailId) {
  this.emailId = emailId;
 }
}


EmailProducer.java
package com.synchronousqueue;

import java.util.concurrent.SynchronousQueue;

public class EmailProducer implements Runnable {

 private SynchronousQueue<ProducerConsumerBean> synchronousQueue;

 public EmailProducer(SynchronousQueue<ProducerConsumerBean> synchronousQueue) {
  super();
  this.synchronousQueue = synchronousQueue;
 }

 @Override
 public void run() {
  while(true) {
   try {
    ProducerConsumerBean producerConsumerBean = new ProducerConsumerBean();
    producerConsumerBean.setEmailId("EmailId");
    this.synchronousQueue.put(producerConsumerBean);
    System.out.println("Producer Produced Email Id");
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }
}


EmailConsumer.java
package com.synchronousqueue;

import java.util.concurrent.SynchronousQueue;

public class EmailConsumer implements Runnable {
 private SynchronousQueue<ProducerConsumerBean> synchronousQueue;

 public EmailConsumer(SynchronousQueue<ProducerConsumerBean> synchronousQueue) {
  super();
  this.synchronousQueue = synchronousQueue;
 }

 @Override
 public void run() {
  while (true) {
   try {
    //Thread.sleep(10000);
    System.out.println("Consumer Started Sending Email to - "
      + this.synchronousQueue.take().getEmailId());
    //Thread.sleep(10000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

}




BulkEmailMarketing.java
package com.synchronousqueue;

import java.util.concurrent.SynchronousQueue;

public class BulkEmailMarketing {

 public static void main(String args[]) throws InterruptedException {
  SynchronousQueue<ProducerConsumerBean> synchronousQueue = new SynchronousQueue<ProducerConsumerBean>();

  EmailProducer producer = new EmailProducer(synchronousQueue);
  EmailConsumer consumer = new EmailConsumer(synchronousQueue);
  
  new Thread(producer).start();
  new Thread(consumer).start();
  
 }
}


Run the above client file in following 2 cases

1) Uncomment 2nd Thread.sleep(10000); code in EmailConsumer.java and run it
Producer Produced Email Id
Consumer Started Sending Email to - EmailId
will be generated as soon as you run. Now, since the Consumer enters into sleep state for 1000ms, Producer won't be able to put() an element. It will enter an element only when consumer reaches at a state to execute take() method again

2) Uncomment 1st Thread.sleep(10000); code in EmailConsumer.java and run it
Nothing is generated. Now, since the Consumer enters into sleep state for 1000ms, Producer won't be able to put() an element. It will enter an element only when consumer reaches at a state to execute take() method. So first output will be generated after 1000ms
Producer Produced Email Id
Consumer Started Sending Email to - EmailId

To download source, click here.

Producer Consumer Using PriorityBlockingQueue Example in Java

Producer Consumer Using PriorityBlockingQueue Example in Java

java.util.concurrent.PriorityBlockingQueue class is an implementation of BlockingQueue. In our earlier example of Producer Consumer in Java using BlockingQueue we understood how ArrayBlockingQueue class is used.

The general difference between the two is that :
1) ArrayBlockingQueue accepts any java object
2) PriorityBlockingQueue accepts class objects that implements the java.lang.Comparable interface

So, the elements from the PriorityBlockingQueue are read in particular order. The ordering is done by the priority part.

One more thing is, iterator of PriorityBlockingQueue does not guarantee a priority order.

Example Implementation: Below class PersonComparable implements a Comparable interface and performs sorting based on Age.

1) Adding 3 PersonComparable objects with Age = 65, 55, 45 in the Producer Thread
2) Removing 3 PersonComparable objects using take() method. Printing the age of 3 PersonComparable object will display ordering in sorted order by Age i.e. 35, 55, 65

package test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;

public class PersonComparable implements Comparable<PersonComparable> {

 private int age;

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 @Override
 public int compareTo(PersonComparable personComparable) {
  int compareAge = ((PersonComparable) personComparable).getAge();
  return this.age - compareAge;
 }

 public static void main(String args[]) {
  final PersonComparable person = new PersonComparable();
  person.setAge(65);
  
  final PersonComparable personOne = new PersonComparable();
  personOne.setAge(55);

  final PersonComparable personTwo = new PersonComparable();
  personTwo.setAge(45);

  final BlockingQueue<PersonComparable> queue = new PriorityBlockingQueue<PersonComparable>();

  new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     queue.put(person); // Age 65
     queue.put(personOne); // Age 55
     queue.put(personTwo); // Age 45
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
  }, "Producer").start();

  new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     System.out.println(queue.take().getAge()); // Age 45 Sorted
     System.out.println(queue.take().getAge()); // Age 55 Sorted
     System.out.println(queue.take().getAge()); // Age 65 Sorted
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
  }, "Consumer").start();
 }
}

CopyOnWriteArrayList in Java Example

CopyOnWriteArrayList in Java Example

java.util.ArrayList that implements the List interface is not a thread safe implementation. Also the iterator of an ArrayList is fail-fast i.e. it throws ConcurrentModificationException when the list gets modified while the iterator of ArrayList object is traversing or iterating through the List object.

CopyOnWriteArrayList is an implementation that belongs to concurrent family in a Collection framework. Iterator of CopyOnWriteArrayList is fail-safe, hence it does not throw ConcurrentModificationException when the list gets modified while the iterator of CopyOnWriteArrayList object is traversing or iterating through the List object.

How it works? Why CopyOnWriteArrayList does not throw ConcurrentModificationException Exception?
When the Iterator object is created from the CopyOnWriteArrayList object, it gets the seperate copy of ArrayList on which the Iterator iterates. So even if remove or add operations are performed on the CopyOnWriteArrayList object, the ArrayList of the Iterator does not gets modified.

Difference between CopyOnWriteArrayList and ArrayList in Java.
1) ArrayList is not thread safe whereas CopyOnWriteArrayList is a thread safe collection that is used in concurrent applications

2) ArrayList Iterator throws ConcurrentModificationException when the list gets modified during Iteraion. But CopyOnWriteArrayList does not throw any ConcurrentModificationException even if the list gets modified during Iteraion.

3) CopyOnWriteArrayList does not support remove() functionality whereas ArrayList has remove() method

package test;

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

public class CopyOnWriteArrayListExample {
    public static void main(String args[]) {
        final CopyOnWriteArrayList<String> copyOnWriteArrayList = 
            new CopyOnWriteArrayList<String>();
        copyOnWriteArrayList.add("Car Insurance");
        copyOnWriteArrayList.add("Online Accounting Degree");
        copyOnWriteArrayList.add("Insurance");
        copyOnWriteArrayList.add("Personal Loan");
        System.out.println("Original CopyOnWriteArrayList :"
                + copyOnWriteArrayList + "\n");
        // new thread to concurrently modify the list
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                copyOnWriteArrayList.add("Car Loans");
                System.out
                        .println("\nConcurrently the list got modified in another thread");
                System.out.println("New CopyOnWriteArrayList :"
                        + copyOnWriteArrayList + "\n");
            }
        }).start();

        Iterator<String> failSafeIterator = copyOnWriteArrayList.iterator();
        while (failSafeIterator.hasNext()) {
            System.out.printf("Iterating the List - " + failSafeIterator.next()
                    + "\n");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}



As shown in the output below :


1) Original List contains 4 Elements
2) The Iterator object got created on the original list before any modification, so Iterator also contains 4 Elements
3) In between the Iteration, CopyOnWriteArrayList added one element in new thread and the CopyOnWriteArrayList now contains 5 elements
4) But the iterator only displayed 4 elements because Iterator operates on different object of CopyOnWriteArrayList i.e. copy of an CopyOnWriteArrayList object.

Original CopyOnWriteArrayList :[Car Insurance, Online Accounting Degree, Insurance, Personal Loan]

Iterating the List - Car Insurance
Iterating the List - Online Accounting Degree
Iterating the List - Insurance

Concurrently the list got modified in another thread
New CopyOnWriteArrayList :[Car Insurance, Online Accounting Degree, Insurance, Personal Loan, Car Loans]
Iterating the List - Personal Loan

ReentrantReadWriteLock ReadWriteLock Java Example

ReentrantReadWriteLock ReadWriteLock Java Example

java.util.concurrent.locks.ReentrantReadWriteLock and java.util.concurrent.locks.ReadWriteLock are two locking mechanisms in java that helps in getting locks in concurrent applications.

It helps in resolving the concurrency error that may get caused due to multiple reading or writing in a shared resource.

For instance, if multiple threads are reading a shared resource all will get consistent values, but what if multiple threads are writing a value to a particular field that is also being read. In this case, there may be an inconsisteny in reading.

The principal behind ReentrantReadWriteLock is
1) Write Lock - If no threads have locked the ReadWriteLock for reading or writing, this can achieve a lock for writing. At a time, only 1 thread gets a lock of ReadWriteLock for writing. And once a thread achieves a lock for writing, no other thread be it reading or writing will not get a lock and all will wait for this lock to get released

2) Read Lock - If no threads have locked the ReadWriteLock for writing, multiple threads can lock the lock for reading.

Thus, Multiple threads can achieve a Read Lock for reading a data, but only a single thread can achieve a lock for Writing.

Consider a below client application to demonstrate the ReadWriteLocks in java. In this, a small stock price application is explained. Multiple readers can read the stock price while only one Writer can update the stock price and when Writer is updating a stock price all other readers and writers enter into wait state.

For Writer, I have five threads and for Reader, I have 15 threads.

LockPojo.java

package com.readWriteLock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockPojo {

 public LockPojo(ReentrantReadWriteLock readWriteLock) {
  super();
  this.readWriteLock = readWriteLock;
  this.readLock = readWriteLock.readLock();
  this.writeLock = readWriteLock.writeLock();
 }

 private ReadWriteLock readWriteLock;

 private Lock readLock;

 private Lock writeLock;

 private Double lastTradedPrice;

 public ReadWriteLock getReadWriteLock() {
  return readWriteLock;
 }

 public void setReadWriteLock(ReadWriteLock readWriteLock) {
  this.readWriteLock = readWriteLock;
 }

 public Lock getReadLock() {
  return readLock;
 }

 public void setReadLock(Lock readLock) {
  this.readLock = readLock;
 }

 public Double getLastTradedPrice() {
  return lastTradedPrice;
 }

 public void setLastTradedPrice(Double lastTradedPrice) {
  this.lastTradedPrice = lastTradedPrice;
 }

 public Lock getWriteLock() {
  return writeLock;
 }

 public void setWriteLock(Lock writeLock) {
  this.writeLock = writeLock;
 }

}


ReadStockPrice.java



package com.readWriteLock;

import java.text.DecimalFormat;

public class ReadStockPrice implements Runnable {

 @Override
 public void run() {
  System.out.println("Reader Started - " + Thread.currentThread().getName());
  this.getLockPojo().getReadLock().lock();
  try {
   Thread.sleep(100);
   DecimalFormat format = new DecimalFormat("#.##");
   System.out.println("Read Stock Price - "
     + format.format(this.getLockPojo().getLastTradedPrice()));
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally {
   this.getLockPojo().getReadLock().unlock();
   System.out.println("Reader Finished - " + Thread.currentThread().getName());
  }
 }

 private LockPojo lockPojo;

 public LockPojo getLockPojo() {
  return lockPojo;
 }

 public void setLockPojo(LockPojo lockPojo) {
  this.lockPojo = lockPojo;
 }

}


WriteStockPrice.java

package com.readWriteLock;

import java.text.DecimalFormat;

public class WriteStockPrice implements Runnable {

 @Override
 public void run() {
  System.out.println("Writer Started - "
    + Thread.currentThread().getName());
  this.getLockPojo().getWriteLock().lock();
  try {
   DecimalFormat format = new DecimalFormat("#.##");
   Thread.sleep(10000);
   this.getLockPojo().setLastTradedPrice(
     ((this.getLockPojo().getLastTradedPrice() * 0.01) + this
       .getLockPojo().getLastTradedPrice()));
   System.out.println("Write Stock Price - "
     + format.format(this.getLockPojo().getLastTradedPrice()));
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally {
   this.getLockPojo().getWriteLock().unlock();
   System.out.println("Writer Finished - "
     + Thread.currentThread().getName());
  }
 }

 private LockPojo lockPojo;

 public LockPojo getLockPojo() {
  return lockPojo;
 }

 public void setLockPojo(LockPojo lockPojo) {
  this.lockPojo = lockPojo;
 }
}


ReadWriteLockTest.java

package com.readWriteLock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {

 public static void main(String args[]) {
  LockPojo lockPojo = new LockPojo(new ReentrantReadWriteLock());
  Double initPrice = new Double(10);
  ReadStockPrice readers = new ReadStockPrice();
  readers.setLockPojo(lockPojo);
  lockPojo.setLastTradedPrice(initPrice);

  WriteStockPrice writers = new WriteStockPrice();
  writers.setLockPojo(lockPojo);

  Thread[] threads = new Thread[20];
  for (int i = 0; i < 20; i++) {
   if (i % 2 == 0 && i < 10)
    threads[i] = new Thread(writers);
   else
    threads[i] = new Thread(readers);
  }
  for (int i = 0; i < 20; i++) {
   threads[i].start();
  }
 }
}


When you will run the application, till the Writer Thread Number 8 is running, all readers will be in wait mode, after that all readers will run at once

Output

Writer Started - Thread-0
Reader Started - Thread-1
Writer Started - Thread-2
Reader Started - Thread-3
Writer Started - Thread-4
Reader Started - Thread-5
Writer Started - Thread-6
Reader Started - Thread-7
Writer Started - Thread-8
Reader Started - Thread-9
Reader Started - Thread-10
Reader Started - Thread-11
Reader Started - Thread-12
Reader Started - Thread-13
Reader Started - Thread-14
Reader Started - Thread-15
Reader Started - Thread-16
Reader Started - Thread-17
Reader Started - Thread-18
Reader Started - Thread-19
Write Stock Price - 10.1
Writer Finished - Thread-0
Read Stock Price - 10.1
Reader Finished - Thread-1
Write Stock Price - 10.2
Writer Finished - Thread-2
Read Stock Price - 10.2
Reader Finished - Thread-3
Write Stock Price - 10.3
Writer Finished - Thread-4
Read Stock Price - 10.3
Reader Finished - Thread-5
Write Stock Price - 10.41
Writer Finished - Thread-6
Read Stock Price - 10.41
Reader Finished - Thread-7
Write Stock Price - 10.51
Writer Finished - Thread-8
Read Stock Price - 10.51
Reader Finished - Thread-9
Read Stock Price - 10.51
Reader Finished - Thread-10
Read Stock Price - 10.51
Reader Finished - Thread-11
Read Stock Price - 10.51
Reader Finished - Thread-12
Read Stock Price - 10.51
Reader Finished - Thread-13
Read Stock Price - 10.51
Reader Finished - Thread-14
Read Stock Price - 10.51
Reader Finished - Thread-15
Read Stock Price - 10.51
Reader Finished - Thread-16
Read Stock Price - 10.51
Reader Finished - Thread-17
Read Stock Price - 10.51
Reader Finished - Thread-18
Read Stock Price - 10.51
Reader Finished - Thread-19


To download source, click here

Thread Join With Timeout Java with example

Thread Join With Timeout Java with example

In our last post, we understood the core basics of join() method of threads.

But the join() method has one disadvantage, it waits indefinetly for the thread to finish its execution in order to resume the joining thread.

join(long milliseconds) is more effective to use as it takes timeout as parameter. So if

Thread Execution Time > milliseconds parameter, then the thread which is waiting will resume its job after milliseconds parameter.

Look at the client below

Main Thread starts its execution
Thread-0 joins main thread with Timeout 5 seconds
But Thread-0 takes 10 seconds to get over
In this case, main thread after 5 seconds will resume its operations and move ahead.

package test;

public class ThreadJoin implements Runnable {

 @Override
 public void run() {
  try {
   System.out.println("Runnable Thread Started - "
     + Thread.currentThread().getName());
   Thread.sleep(10000);

  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.out.println("Runnable Over - "
    + Thread.currentThread().getName());
 }

 public static void main(String args[]) throws Exception {
  System.out.println("Main Started");
  Thread thread = new Thread(new ThreadJoin());

  thread.start();
  // Main thread will wait for 5 seconds and
  // then move ahead even if this thread has
  // not finished its execution
  thread.join(5000);

  System.out.println("Main Thread Over");
 }

}