Thread local

  1. Thread local class provides thread local variables.
  2. Thread local class maintains values per thread basis.
  3. Each thread local object maintains a separate value like user id, transaction id etc for each thread that access the object.
  4. Thread can access its local value, can manipulate its value and even can remove its value.
  5. In every part of the code which is execute by the Thread we can access its local variable.
  6. Example : Consider a servlet which invokes some business methods, we have a requirement to generate a unique transaction ID for each and every request and we have to pass this transaction id to the business methods. For this requirement we can use thread local to maintain a separate transaction id for every request i.e for every thread.
  7. Thread local class introduced in java 1.2 version and enhanced in 1.5 version
  8. Thread local can be associated with thread scope.
  9. Total code with is executed by the thread has access to the corresponding thread local variable.
  10. A thread can access its own local variables and can’t access other threads local variable.
  11. Once thread entered into dead state all its local variables are by default eligible for Garbage collection.

Constructor :

ThreadLocal tl = new ThreadLocal();
• creates a new ThreadLocal variable

Methods :

• Object get()
Returns the value of thread local variable associated with current thread.

• Object initialValue()
Returns initial value of thread local variable associated with current thread.
The default implementation of this method returns null
To customize our own initial value we have to override this method

• void set(Object newValue)
To set a new value

• void remove()
To remove the value of Thread local variable associated with current Thread.
It is newly added method in java 1.5 version.
After removal if we are trying to access, it will be reinitialized once again by invoking its initial value method.

Example1 :

package com.demo11;

public class ThreadLocalDemo1 {
	public static void main(String[] args) {
		ThreadLocal tl = new ThreadLocal();
		System.out.println(tl.get());
		tl.set("Tyson");
		System.out.println(tl.get());
		tl.remove();
		System.out.println(tl.get());
	}
}

Overriding of initial value method of Thread Local

public class ThreadLocalDemo2 {
	public static void main(String[] args) {
		ThreadLocal tl = new ThreadLocal() {
			public Object initialValue() {
				return "Justin";
			}
		};
		System.out.println(tl.get());
		tl.set("Tyson");
		System.out.println(tl.get());
		tl.remove();
		System.out.println(tl.get());
	}
}

Example of ThreadLocal in Use :

public class ThreadLocalDemo3 {
	public static void main(String[] args) throws InterruptedException {
		Temp x = new Temp();
		Thread t1 = new Thread(x,"ThreadA");
		Thread t2 = new Thread(x,"ThreadB");
		t1.start();
		t1.join();
		t2.start();
	}
}
class Temp implements Runnable{
	int x;
	ThreadLocal y = new ThreadLocal();

	@Override
	public void run() {
		if(Thread.currentThread().getName().equalsIgnoreCase("ThreadA")) {
			x = 100;
			y.set(100);
		}
		System.out.println("Thread Name "+Thread.currentThread().getName()+" Int Value :"+x+" Thread Local Value : "+y.get());
	}
}

A Separate Thread Id for every Thread can be implemented using Thread Local

public class ThreadLocalDemo4 {
	public static void main(String[] args) {
		CustomerThread c1 = new CustomerThread("Thread A");
		CustomerThread c2 = new CustomerThread("Thread B");
		CustomerThread c3 = new CustomerThread("Thread C");
		CustomerThread c4 = new CustomerThread("Thread D");
		c1.start();
		c2.start();
		c3.start();
		c4.start();
	}
}

class CustomerThread extends Thread{
	static Integer custId=0;
	public static ThreadLocal th1 = new ThreadLocal() {
		protected Integer initialValue() {
			return ++custId;
		}
	};
	CustomerThread(String name){
		super(name);
	}
	
	public void run() {
		System.out.println(Thread.currentThread().getName()+" executing with id "+th1.get());
	}
}

ThreadLocal Vs Inheritance (InheritableThreadLocal class)

  • Parent Threads ThreadLocal variable by default not available to the child thread, if we want to make parent threads ThreadLocal variable value available to the child thread then we shlould go for InheritableThreadLocal class.
  • By default child threads value is exactly same as parent Threads value but we can provide customized value for child Thread by overriding ChildValueMethod.
  • InheritableThreadLocal is the child class of ThreadLocal and Hence all methods present in thread local by default available to InheritableThreadLocal.
  • In Addition to this method it contains only one method
    public Object childValue(Object parentValue)
public class InheritableThreadLocalDemo1 {
	public static void main(String[] args) {
		new ParentThread().start();
	}
}
class ParentThread extends Thread{
	static ThreadLocal tl = new ThreadLocal();
	static InheritableThreadLocal itl = new InheritableThreadLocal();
	public void run() {
		tl.set("Parent Value");
		itl.set("Parent Value");
		new ChildThread().start();
	}
}
class ChildThread extends Thread{
	public void run() {
		System.out.println("Thread Local Value : "+ParentThread.tl.get());
		System.out.println("Inheritable Thread Local Value : "+ParentThread.itl.get());
	}
}

Callable and Future

  • In the case of runnable job Thread won’t return anything after completing the job.
  • If a thread is required to return some result after execution then we should go for callable.
  • Callable interface contains only one method call()
    public Object call() throws Exception.
  • If we submit a callable object to executor then after completing the job thread returns an Object of type Future i.e Future object can be used to retrieve the result from callable job.
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class CallableDemo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		MyCallable[] jobArray = { new MyCallable(10),new MyCallable(20),new MyCallable(30),new MyCallable(40),new MyCallable(50)};
		ExecutorService service = Executors.newFixedThreadPool(3);
		for(MyCallable job : jobArray) {
			Future f = service.submit(job);
			System.out.println(f.get());
		}
		service.shutdown();
	}
}
class MyCallable implements Callable{

	int number;
	MyCallable(int number){
		this.number = number;
	}
	
	public Object call() throws Exception {
		System.out.println("Thread execution started for "+number+" Thread Name : "+Thread.currentThread().getName());
		int total=0;
		for(int i=0;i<=number;i++) {
			total = total + i;
		}
		return total;
	}
}

Difference between Runnable and Callable

RunnableCallable
1. If a thread is not required to return anything after completing the job then we should use Runnable1. If a thread is required to return something after completing the job then we should go for callable.
2. Runnable interface contains only one method run()2. Callable interface contains only one method call()
3. Runnable job not required to return anything and hence return type of run method is void3. Callable job is required to return something and hence return type of call method is object.
4. Within the run method if there is any chance of raising checked exception we need to handle it with try catch because we can’t use throws keyword in run method4.With in call method if there is any chance of raising checked exception we are not required to handle it using try catch because call method already throws exception.
5. Runnable interface present in java.lang package5. Callable interface present in java.util.concurrent package
6. Introduced in java 1.0 version6. Introduced in java 1.5 version

Calculating execution time of program in java 8

  • Instance is a java 8 datime time API object
  • TimeUnit class which class sleep method indirectly class Thread.sleep method but we use TimeUnit class because it is more readable.
  • We calculate the difference between instance using Duration class and print it at the end
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;

public class CalculateExecutionTime {
	public static void main(String[] args) throws InterruptedException {
		Instant start = Instant.now();
		TimeUnit.SECONDS.sleep(5);
		Instant finish = Instant.now();
		long timeElapsed = Duration.between(start, finish).toMillis()/1000;  //in millis
		System.out.println("Execution time in Seconds: "+timeElapsed);
	}
}

Thread pools (Executor Framework)

  1. Creating a new Thread for every job may create performance and memory problems,To overcome this problem we should go for Thread pool.
  2. Thread pool is a pool of already created Threads ready to do our job.
  3. Java 1.5 version introduces Thread pool framework to implement thread pools.
  4. Thread pool framework also know as executor framework.
  5. We can create a thread pool as follows
    ExecutorService service = Executors.newFixedThreadPool(int threadCount);
  6. We can submit a runnable job by using submit method
    service.submit(job)
  7. We can shutdown executor service by using shutdown method
    service.shutdown()
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorFrameworkDemo {
	public static void main(String[] args) {
		MyRunnable[] jobArray = {
				new MyRunnable("Tyson"),
				new MyRunnable("Justin"),
				new MyRunnable("Martin"),
				new MyRunnable("Jake"),
				new MyRunnable("Fade"),
				new MyRunnable("Luke")
		};
		ExecutorService service = Executors.newFixedThreadPool(3);
		for(MyRunnable job : jobArray) {
			service.submit(job);
		}
		service.shutdown();
	}
}
class MyRunnable implements Runnable{
	String name;
	MyRunnable(String name){
		this.name = name;
	}
	public void run() {
		System.out.println("Thread execution started for "+name+" Thread Name : "+Thread.currentThread().getName());
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Thread execution completed for "+name);
	}
}
  • In the above example three threads are responsible to execute six jobs so that a single thread can be reused for multiple jobs
  • Note : While designing web servers and application servers we can use thread pool concept.

ReentrantLock Class

  1. It is an Implementation class of lock interface and it is the directly child class of object.
  2. Reentrant means a thread can acquire same lock multiple times without any issue.
  3. Internally reentrant lock increments threads personal count when ever we call lock method and decrements count value whenever thread calls unlock method and lock will be release only when count reaches zero

Constructors :

  • ReentrantLock l = new ReentrantLock()
    1. Creates a instance of reentrant lock
    2. By befault faireness in set to false
  • ReentarantLock l = new ReentrantLock(boolean fairness)
    1. Creates Reentrant lock with given fainess policy
    2. If the fairness is true then longest waiting thread can acquire the lock if it is available i.e it follows FCFS(First Come First Serve) policy.
    3. If the fairness is false then which waiting thread will get the chance we can expect.

Important methods of ReentrantLock class

  • void lock()
  • void trylock()
  • void trylock(long l,TimeUnit unit)
  • void lockInterruptably()
  • void unlock()
  • int getHoldCount()
  • boolean isHeldByCurrentThread()
  • int getQueueLength
  • Collection getQueuedThreads()
  • boolean hasQueuedThreads()
  • boolean isLocked()
  • boolean isFair()
  • Thread getOwner()
  • int getHoldCount()
    Returns number of holds on this lock by current Thread
  • boolean isHeldByCurrentThread()
    Returns true if and only lock is hold by current Thread
  • int getQueueLength()
    Returns number of Threads waiting for the lock
  • Collection getQueuedThreads()
    It returns a collection of Threads which are waiting to get the lock
  • boolean hasQueuedThreads()
    It returns true if any thread waiting to get the lock
  • boolean isLocked()
    Returns true if the lock is acquired by some thread.
  • boolean isFair()
    Returns true if the fairness policy with the true value.
  • Thread getOwner()
    Returns the thread which acquires the lock
public class ReentrantLockDemo1 {
	public static void main(String[] args) {
		ReentrantLock l = new ReentrantLock();
		l.lock();
		l.lock();
		System.out.println(l.isLocked());
		System.out.println(l.isHeldByCurrentThread());
		l.unlock();
		System.out.println(l.isHeldByCurrentThread());
		System.out.println(l.isLocked());
		l.unlock();
		System.out.println(l.isLocked());
		System.out.println(l.isFair());
	}
}

Demo of lock() method

public class ReentrantLockDemo2 {
	public static void main(String[] args) {
		Display d = new Display();
		MyThread t1 = new MyThread(d,"Tyson");
		MyThread t2 = new MyThread(d,"Justin");
		MyThread t3 = new MyThread(d,"Martin");
		t1.start();
		t2.start();
		t3.start();
	}
}
class MyThread extends Thread{
	Display d;
	String name;
	MyThread(Display d,String name){
		this.d = d;
		this.name = name;
	}
	public void run() {
		try {
			d.wish(name);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
class Display{
	ReentrantLock l = new ReentrantLock();
	
	public void wish(String name) throws InterruptedException {
		l.lock();
		for(int i=0;i<5;i++) {
			System.out.println("Hello "+name);
			Thread.sleep(500);
		}
		l.unlock();
	}
}

Demo program from trylock()

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo3 {
	public static void main(String[] args) {
		MyThread1 t1 = new MyThread1("First Thread ");
		MyThread1 t2 = new MyThread1("Second Thread ");
		t1.start();
		t2.start();
	}
}
class MyThread1 extends Thread{
	static ReentrantLock l = new ReentrantLock();
	MyThread1(String name){
		super(name);
	}
	public void run() {
		if(l.tryLock()) {
			for(int i=0;i<10;i++) {
				System.out.println("Hello "+Thread.currentThread().getName()+i);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			l.unlock();
		}else {
			System.out.println(Thread.currentThread().getName()+" Unable to get lock");
		}
	}
}

Demo program for tryLock(long time,TimeUnit unit)

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo3 {
	public static void main(String[] args) {
		MyThread1 t1 = new MyThread1("First Thread ");
		MyThread1 t2 = new MyThread1("Second Thread ");
		t1.start();
		t2.start();
	}
}
class MyThread1 extends Thread{
	static ReentrantLock l = new ReentrantLock();
	MyThread1(String name){
		super(name);
	}
	public void run() {
		do {
			try {
				if(l.tryLock(3000,TimeUnit.MILLISECONDS)) {
					System.out.println(Thread.currentThread().getName()+" got the lock");
					for(int i=0;i<10;i++) {
						System.out.println("Hello "+Thread.currentThread().getName()+i);
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println(Thread.currentThread().getName()+" releasing the lock");
					l.unlock();
					break;
				}else {
					System.out.println(Thread.currentThread().getName()+" : Unable to get lock will be trying again");
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}while(true);
	}
}

Lock Interface of java.util.concurrent package

The problems with Traditional synchronized keyword “

  1. We are not having any flexibility to try for a lock without waiting
  2. There is no way to specify maximum waiting time for a Thread to get lock so that thread will wait until getting the lock which may create performance problems which may cause dead lock
  3. If a Thread releases the lock then which waiting thread will get that lock we are not having any control on this.
  4. There is no API to list out all waiting threads for a lock
  5. We use Synchronized keyword at method level or within a method(synchronized block) and it is not possible to use across multiple methods.
  6. To overcome these problems java 1.5 introduced java.util.concurrent.locks package
  7. It also provides several enhancement to the programmer to provide more control on concurrency.

Lock Interface

  1. Lock object is similar to implicit lock acquired by a Thread to execute synchronized method or synchronized block.
  2. Lock implementations provide more extensive operations that traditional implicit locks.

Important methods of lock interface

void lock()
We can use this method to acquire a lock. If lock is available then immediately the current thread will get that lock, if the lock is not already available it will wait until getting lock. If behaves exactly like Traditional synchronized keyword.

boolean tryLock()
1. This method is used to acquire the lock without waiting.
2. If the lock is available then the thread acquires the lock and returns true.
3. If the lock is not available then this method returns false and it can continue its execution without waiting.
4. Using this method thread will never be entered into waiting state.

boolean tryLock(long time,TimeUnit unit)
1. If lock is available then thread will get the lock and continue its execution
2. If the lock is not available then the thread will wait until specified amount of time.
3. If the lock is not available after the time passes then thread can continue its execution

void lockInterruptibly()
1. Acquires the lock if it is available and returns immediately.
2. If the lock is not available then it will wait
3. While waiting if the thread is interrupted then thread won’t get the lock

void unlock()
1. Releases the lock
2. To call this method the current thread should be the owner of the lock otherwise we will get runtime exception saying IllegalMonitorState exception.

TimeUnit

TimeUnit is an enum present in java.util.concurrent package

enum TimeUnit
{
	NANOSECONDS,
	MICROSECONDS,
	MILLISECONDS,
	SECONDS,
	MINUTES,
	HOURS,
	DAYS;
}

Thread Group

  1. Based on functionality we can group threads into a single unit which is nothing but thread group i.e Thread group contains a group of Threads.
  2. In addition to threads, thread group can also contain sub thread groups
  3. The main advantage of maintaining Thread in the form of Thread group is we can perform common operations very easily.
  4. Every thread in java belongs some group, main thread belongs to main group.
  5. Every thread group in java is a child group of system group either directly or indirectly. Hence system group acts as root for all thread groups in java.
  6. System group contains several system level threads like :
    a. Finalizer (Garbage Collector)
    b. Reference Handler
    c. Signal Dispatcher
    d. Attach Listener
    e. Main Thread group
    etc
  7. ThreadGroup is a java class present in java.lang package and it is direct child class of object.
  8. Threads in the Thread Group that already have higher priority won’t be affected when a priority of their Thread Group changes(setMaxPriority()) but for newly added Threads this priority is applicable.
public class ThreadGroupDemo {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getThreadGroup().getName());
		System.out.println(Thread.currentThread().getThreadGroup().getParent().getName());
	}
}

Output :

Constructors :

  1. ThreadGroup g = new ThreadGroup(String group);
    Creates a new Thread group with the specified group name.
    The parent of the new group is the thread group of currently executing thread.
    Example : ThreadGroup g = new ThreadGroup(“First Group”);
  2. ThreadGroup g = new ThreadGroup(ThreadGroup parentGroup,String groupName);
    Creates a new Thread group with specified group name.
    The parent of this new thread group is specified parent group.
    Example : ThreadGroup g1 = new ThreadGroup(g,”Second Group”);
ThreadGroup g = new ThreadGroup(String group);
ThreadGroup g = new ThreadGroup(ThreadGroup parentGroup,String groupName);

public class ThreadGroupDemo {
	public static void main(String[] args) {
		ThreadGroup g = new ThreadGroup("FirstGroup");
		System.out.println(g.getParent().getName());
		ThreadGroup g1 = new ThreadGroup(g,"SecondGroup");
		System.out.println(g1.getParent().getName());
	}
}

Output

system group --> main group --> First Group --> Second Group

Important Method of Thread Group Class :

Sting getName()
int getMaxPriority()
void setMaxPriority(int p)
ThreadGroup getParent()
void list() //print information about thread group
int activeCount() //returns number of active threads present in the Thread group
int activeCountGroup() //returns number of active group present in the current thread group
int enumeration(Thread[] t) //to copy all active Threads(also sub threads) of this thread group into array
int enumeration(ThreadGroup[] t) //To copy all active sub Thread Groups into thread group array
boolean isDaemon() //To check if a the ThreadGroup is a Deamon group 
void setDaemon(boolean b) 
void interrupt() //To interrupt all waiting or sleeping thread present in the Thread Group 
void destroy() //To destroy ThreadGroup and its sub thread groups
  1. Threads in the Thread Group that already have higher priority won’t be affected when a priority of their Thread Group changes(setMaxPriority()) but for newly added Threads this priority is applicable.
public class ThreadGroupDemo2 {
	public static void main(String[] args) {
		ThreadGroup g1 = new ThreadGroup("Group 1");
		Thread t1 = new Thread(g1,"Thread 1");
		Thread t2 = new Thread(g1,"Thread 2");
		g1.setMaxPriority(3);
		Thread t3 = new Thread(g1,"Thread 3");
		System.out.println(t1.getPriority());//5
		System.out.println(t2.getPriority());//5
		System.out.println(t3.getPriority());//3
	}
}

2. activeCount() and activeGroupCount() and list()

package com.demo8;

public class ThreadGroupDemo3 {
	public static void main(String[] args) throws InterruptedException {
		ThreadGroup g1 = new ThreadGroup("Group 1");
		ThreadGroup g2 = new ThreadGroup(g1,"Group 2");
		MyThread t1 = new MyThread(g1,"Thread 1");
		MyThread t2 = new MyThread(g1,"Thread 2");
		t1.start();
		t2.start();
		System.out.println("Active Thread count : "+g1.activeCount());
		System.out.println("Active Thread count : "+g1.activeGroupCount());
		g1.list();
		t1.join();
		t2.join();
		System.out.println("Active Thread count : "+g1.activeCount());
		System.out.println("Active Thread count : "+g1.activeGroupCount());
		g1.list();
	}
}
class MyThread extends Thread{
	MyThread(ThreadGroup groupName,String name){
		super(groupName,name);
	}
	public void run() {
		System.out.println("Child Thread");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

Output :

Thread Group hierarchy of the above program : 
system group --> main group --> group 1 --> group 2

3. int enumeration(Thread[] t) and int enumeration(ThreadGroup[] t)
Write a program to display all active thread names belonging to system group and its child groups.

public class ThreadGroupDemo4 {
	public static void main(String[] args) {
		ThreadGroup systemGroup = Thread.currentThread().getThreadGroup().getParent();
		Thread[] threadArray = new Thread[systemGroup.activeCount()];
		systemGroup.enumerate(threadArray);
		for(Thread t : threadArray) {
			System.out.println("Thread Name : "+t.getName()+" -----------> Is Demon : "+t.isDaemon());
		}
	}
}

Interrupt a sleeping,waiting thread.

interrupt() method interrupts a sleeping thread during its sleeping time.

  • In the below example the main thread waits for the MyThread to complete using join method for 2 seconds.
  • If the MyThread does not completes its execution in 2 seconds, then main thread interrupts MyThread and check if the Thread is still alive in loop.
class MyThread extends Thread { 
	public void run() 
	{
		for (int i = 0; i < 500; i++) {
			System.out.println("Child Thread executing : "+i);
			try { 
					Thread.sleep(500); 
				} 
			catch (InterruptedException e) { 
				System.out.println("Interrupted Exception occured"); 
			}
		}
	} 
} 

class Test { 
	public static void main(String[] args) 
			throws InterruptedException 
	{ 
		MyThread thread = new MyThread(); 
		thread.start(); 
		while(thread.isAlive()) {
			thread.join(2000);
			thread.interrupt();
		}
		System.out.println("Main thread execution completes"); 
	} 
} 

Green Thread stop(), suspend() and resume()

Java multi threading concept is implemented by using following two models

  1. Green Thread model
  2. Native OS model

Green Thread model

  1. The Thread which is managed completely by JVM without taking underlying OS support is called Green Thread.
  2. Very few operating system like solaris os provides support for Green Thread model.
  3. Green Thread model is deprecated and not recommended to use.

Native OS model

  1. The thread which is managed by the JVM with the help of underlying OS, is called native OS model.
  2. All windows based operating system provide support for native OS model.

How to stop a thread in java ?

  1. We can stop a thread execution by using stop() method of Thread class.
  2. public void stop()
  3. If we call stop() method then immediately the thread will be entered into dead state
  4. stop() method is deprecated and not recommended to use.
public class DemoThread {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		myThread.start();
		System.out.println("End of main Thread");
		myThread.stop();
	}
}
class MyThread extends Thread{
	public void run() {
		for(int i = 0; i<10; i++) {
			System.out.println("Executing child thread "+i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
				System.out.println(e);
			}
		}
	}
}

How to suspend and resume a thread in java ?

  1. We can suspend a thread by using suspend() method of thread class then immediately the thread will be entered into suspended state.
  2. We can resume a suspended thread by using resume() method of thread class, then suspended thread can continue its execution.
    public void suspend();
    public void resume();
  3. These methods are deprecated and not recommended to use.
public class DemoThread {
	public static void main(String[] args) throws InterruptedException {
		MyThread myThread1 = new MyThread();
		myThread1.start();
		System.out.println("End of main Thread");
		Thread.sleep(2000);
		System.out.println("Suspending child thread");
		myThread1.suspend();
		System.out.println("Main thread will sleep for 10 seconds");
		Thread.sleep(10000);
		System.out.println("Resuming child thread");
		myThread1.resume();
	}
}
class MyThread extends Thread{
	public void run() {
		for(int i = 0; i<10; i++) {
			System.out.println("Executing child thread "+i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
				System.out.println(e);
			}
		}
	}
}