Você está na página 1de 17

MULTI THREADING

THE AIM OF MULTI THREADING IS TO PROVIDE CONCURRENT EXECUTION.


[SIMULTANEOUS/PARELLELY PERFORMING MULTIPLE OPERATIONS]
DEFNITION OF THREAD:-A FLOW OF CONTROL IS KNOWN AS THREAD.
THE PURPOSE OF THREAD IS EXECUTING THE LOGIC OF JAVA PROGRAM
WHICH IS RETURN IN THE FORM OF METHODS CONCURRENTLY.
IF A JAVA PROGRAM CONTAINS MULTIPLE THREADS THEN IT IS CALLED MULTI
THREADED PROGRAM.
THE LANGUAGE LIKE C,C++.....E.T.C ARE TREATED AS SINGLE THREADED
MODELLING LANGUAGES BECAUSE THEY EXECUTION ENVIRONMENT
CONTAINS SINGLE FLOW OF CONTROL,PROVIDES
SEQUENTIALEXECUTION,TAKES MORE EXECUTION TIME AND DOES NOT
CONTAIN ANY LIBRARY FOR DEVELOPMENT OF MULTI THREADED APPS.
THE LANGUAGE LIKE JAVA,.NET ARE TREATED AS MULTI THREADED
MODELLING LANGUAGES BECAUSE THEIR EXECUTION ENVIRONMENT
CONTAINS MULTIPLE FLOW OF CONTROLS,PROVIDES CONCURRENT
EXECUTION,TAKES LESS TIME TO EXECUTE AND CONTAINS EFFECTIVE API'S
FOR DEVELOPMENT OF THREAD BASED APPS.
WHENEVER WE WRITE ANY JAVA PROGRAM THERE EXISTS TWO TYPES OF
THREADS THEY ARE 1)FOREGROUND THREAD/CHILD THREAD
2)BACK GROUND THREAD/PARENT THREAD
FORE GROUND THREAD ALWAYS EXECUTES LOGIC OF THE JAVA PROGRAM
WHICH IS WRITTEN IN THE FORM OF METHODS CONCURRENTLY.
A BACKGROUND THREAD ALWAYS MONITORS THE EXECUTION STATUS OF
FOREGROUND THREADS.
BY DEFAULT EVERY JAVA PROGRAM CONTAINS SINGL FOREGROUND THREAD
AND SINGLE BACKGROUND THREAD,PROGRAMATICALLY ONE CAN CREATE
MULTIPLE FOREGROUND THREADS AND RECOMMENDED TO CREATE ONE
BACKGROUND THREADS.
THE REALTIME IMPLEEMENTATIONS OF MULTI THREADING IS THAT TO
DEVELOP REAL WORLD SERVER SOFTWARE LIKE
TOMCAT,WEBLOGIC,WEBSPHERE....ETC.IN OTHERWORDS ALL THE SERVERS

SOFTWRE'S DEVELOPED BY SERVER VENDORS IN JAVA LANGUAGE BY USING


MULTI THEREADING CONCEPT.
HENCE MULTI THREADING OF JAVA ISONE OF THE SPECIALIZED FORM OF
MULTI TASKING OF O.S.
HOW DO YOU JUSTIFY EACH AND EVERY JAVA PROGRAM IS MULTITHREADED?
ANS:-WHEN EVER WE EXECUTE A JAVA PROGRAM THE LOGIC OF JAVA
PROGRAM IS EXECUTED BY ONE OF THE THREAD KNOWN AS FOREGROUND
THREAD.INTERNALLY TO MONITOR THE EXECUTION STATUS OF THE
FOREGROUND THREAD ONE MORE THREAD IS CREATED KNOWN AS
BACKGROUND THREAD.SO A JAVA PROGRAM CONTAINS TWO THREADS BY
DEFAULT. HENCE,EVERY JAVA PROGRAM IS MULTI THREADED.
WHAT ARE THE DIFFERENCES BETWEEN PROGRAM AND PROCESS?
ANS:PROGRAM

PROCESS

*SET OF OPTIMIZED INSTRUCTIONS IS *A PROGRAM UNDER EXECUTION IS


KNOWN AS PROGRAM.
KNOWN AS PROCESS.
**PROGRAM WILL RESIDES IN THE
**PROCESSES RESIDES IN THE MAIN
SECONDARY MEMORY FOR ALONG
MEMORY FOR A LIMITED SPAN OF
TIME UNTIL WE DELETE.
TIME UNTIL THE EXECUTION
***PROGRAMATICALLY A PROGRAM
FINISHED.
CAN BE TREATED AS STATIC.
***PROGRAMATICALLY A PROCESS
CAN BE TREATED AS DYNAMIC
OBJECT.

DEFNITION OF CPU BURST TIME:THE AMOUNT OF TIME TAKEN BY THE THREAD/PROCESS FROM CPU FOR ITS
COMPLETE EXECUTION IS CALLED CPUBURST TIME.
CPU BURST TIME IS DECIDED BY O.S WHEN THE PROGRAMIS ABOUT TO
EXECUTE.
IN REALWORLD WE WRITE TWO TYPES OF APPLICATIONS...PROCES BASED Vs
THREAD BASED APPS (OR) NON MULTITASKING Vs MULTI TASKING APPS:-

PROCESS BASED APPS

THREAD BASED APPS

*PROCESS BASED
*THREAD BASED APPS(TBA)
APPS(PBA)CONTAINS SINGLE FLOW
PROVIDES MULTIPLE FLOW OF
OF CONTROL.
CONTROLS.
**EG:-ALL THE SINGLE THREAD
**EG:- ALL THE MULTI THREAD
MODELLING LANG RELATED APPS
MODELLING LANG RELATED APPS
ARE TREATED AS (PBA).
ARE TREATED AS (TBA).
***IN PBA CONTEXT SWITCHING IS
***IN TBA CONTEXT SWITCHING IS
MORE.
LESS.
****IN PBA EXECUTION TIME IS
****IN TBA EXECUTION TIME IS LESS.
MORE.
*****IN TBA,IRRESPECTIVE OF NO OF
*****IN PBA FOR EACH&EVERY SUBSUB-PROGRAM THERE EXISTS ONLY
PROGRAM THERE EXISTS A SEPARATE ONE ADDRESS SPACE.
ADDRESS SPACE.
******ALL THE TBA RE TREATED AS
******ALL THE PBA RE TREATED AS
LIGHT WEIGHT COMPONENTS.
HEAVY WEIGHT COMPONENTS.
*******TBA PROVIDES BOTH
*******PBA PROVIDES ONLY
CONCURRENT EXECUTION AND
SEQUENTIAL EXECUTION BUT NOT
SEQUENTIAL EXECUTION.
CONCURRENT.
DEFNITION OF ADDRESS SPACE:-IT IS AN AMOUNT OF TEMPORARY MEMORY
SPACE CREATED BY O.S ON STACK MEMORY FOR THE TEMPORARY
EXECUTION OF METHOD.
DEFNITION OF CONTEXT SWITCHING:-IT IS THE MECHANISM OF SWITCH THE
CPU FROM ONE ADRESS SPACE TO ANOTHER SPACE.
*A HEAVY WEIGHT COMPONENT ALWAYS TAKES MORE EXECUTION TIME .AND
LIGHT WEIGHT COMPONENT TAKES LESS EXECUTION TIME.
NOTE:*FOR THE BEST APPS DEVELOPMENT CONTEXT SWITCHING MUST BE
LESS.
**EACH & EVERY TBA IS ONE OF THE PBA IN WHICH THERE EXISTS ONE MAIN
PROCESS AND IT INTURNS CREATES NO OF SUB PROCESS.IN JAVA
PROGRAMMING MAIN PROCESS IS CALLED "THREAD GROUP NAME"AND SUB
PROCESS ARE CALLED "FOREGROUND THREADS" MEANT FOR EXECUTING
THE METHOD CONCURRENTLY.

*WHERE AS A PBA WILL BE TREATED AS PBA IN EXECUTION BUT NOT


TREATED AS TBA BECAUSE AT THE TIME OF EXECUTING PBA IT CONTAINS
ONLY ONE FLOW OF CONTROL.[AND IT IS CALLED GREEN THREAD.}
STATES/LIFE CYCLE OF A THREAD:THE NO OF STAGES/BREAKING POINTS
OCCURING IN THE EXECUTION OF LOGIC OF THE JAVA PROGRAM WHICH IS
WRITTEN IN THE FORM OF USER DEFINED METHODS BY THE THREAD ARE
CALLED STATES OF THE THREAD.
*STATES OF A THREAD ARE CLASSIFIED INTO 5 STEPS THEY ARE
NEW STATE
READY STATE
RUNNING STATE
WAITING STATE
HALTED/DEAD STATE.

-NEW STATE:-IN THIS STATE THREAS IS CREATED AND IT IS ABOUT TO ENTER


INTO MAIN MEMORY.
READY STATE:IN THIS STATE THE THREAD IS ENTERES INTO MAIN MEMORY ,MEMORY
SOACE IS ALLOCATED FOR THE THREAD AND FIRST TIME WAITING FOR THE
CPU FOR EXECUTING THE LOGIC OF JAVA PROGRAM.
RUNNING STATE:IN THIS STATE THE THREAD IS UNDER THE CONTROL OF CPU,IN
OTHERWORDS AS LONG AS THREAD IS EXECUTING LOGIC OF THE JAVA
PROGRAM THEN THE STATE OF THREAD IS IN RUNNING STATE.
HALTED STATE:IN THIS STATE THE THREAD COMPLETES THE TOTAL EXECUTION ,IN
OTHERWORDS WHEN THE THREAD COMPLETE ITS TOTAL CPU BURST TIME
THEN THE STATE OF THE THREAD IS HALTED
WAITING STATE:A THREAD IS SAID TO BE IN WAITING STATE IFF IT SATISFIES ANY OF THE
FOLLOWING FACTORS

1)THREAD COMES TO WAITING STATE FOR REMAINING BURST TIME.


2)SUSPENDING THE CURRENT EXECUTING THREAD.
3)MAKING THE CURRENTLY RUNNING THREAD TO SLEEP FOR PERIOD OF
TIME IN TERMS OF MILLI SECONDS.
4)MAKING THE CURRENTLY EXECUTING THREAD TO WAIT WITH TIME.
5)MAKING THE CURRENTLY EXECUTING THREAD TO WAIT WITHOUT TIME.
6)JOINING THE THREADS.
Q)WHAT DO YOU JUSTIFY THREAD OF JAVA EXECUTES CONCURRENTLY?
ANS:-IF WE ASSUME THREADS ARE EXECUTING WITH THE DIFFERENCE OF
HRS,MIN,SEC THEN SUCH THREAD EXECUTION IS CONSIDERED TO BE
SEQUENTIAL EXECUTION[SLOWEST]AND NOT FOLLOWED IN JAVA
PROGRAMMING.IF THREADS OF JAVA EXECUTING WITH THE DIFFERENCE OF
MS OF TIME THEN SUCH EXECUTIONS IS CONSIDERED TO BE CONCURRENT
EXECUTION[FASTEST] BECAUSE JAVA PROGRAMMER IS UNABLE TO
DIFFERENTIATE THE DIFFERENCE OF MS OF TIME AND IT IS FOLLOWED IN
THE JAVA PROGRAMMING
HENCE DURING THE EXECUTION OF MULTI THREADING APPS ALL THE
THREADS ARE EXECUTING WITH THE DIFFERENCE OF MS OF TIME BY
FOLLOWING ROUND ROBIN ALGORITH CONCURRENTLY.
NOTE:NEW STATE& HALTED STATE ARE CALLED OUT OF MEMORY STATES
AND WHOSE EXECUTION STATUS IS FALSE.READY,RUNNING7WAITING STATES
ARE CALLED IN MEMORY STATES AND WHOSE EXECUTION STATUS IS TRUE.
DEFNITION OF PCB/JCB:-[PROCESS CONTROL BLOCK] IS ONE OF THE
BUFFER[TEMPORARY MEMORY SPACE] CREATED BY O.S FOR EACH & EVERY
THREAD WHEN IT IS ENTERED INTO READY STATFIRST TIME AND WHOSE
PURPOSE IS TO CONTAIN TEMPORARY EXECUTION DETAILS OF THE THREAD.
CREATING A THREAD IN JAVA:-IN JAVA PROGRAMMING WE CAN CREATE
THREADS [FLOW OF CONTROL]BY USING 2 APPROACHES----JAVA.LANG.THREAD
--------------------------------------------------BY USING JAVA.LANG.RUNNABLE
INTERFACE
BY USING JAVA.LANG.THREAD:-

BY USING JAVA.LANG.THREAD CLASS WE CAN CREATE ITS OBJECT(FLOW OF


CONTROL)IN 3 WAYS THEY ARE
--------BY USING NEW OPERATOR
Thread t1=new Thread();
----BY USING FACTORY METHOD
Thread t2=Thread.CurrentThread();
AN OBJECT OF SUB CLASS OF JAVA.LANG.THREAD IS ALSO AN OBJECT OF
JAVA.LANG.THREAD.
class Th1 extends Thread
{
----------------------}
Th1 t1=new Th1();
HERE T1 IS AN OBJECT OF Th1 .Th1 IS THE SUBCLASS OF
JAVA.LANG.THREAD.INDIRECTLY T1 IS AN OBJECT OF JAVA.LANG.OBJECT.
PROFILE OF JAVA.LANG.THREADDATA MEMBERS:Public Static Final Int MAX-PRIORITY(=10)
Public Static Final Int NORM_PRIORITY(=5)
Public Static Final Int MIN_PRIORITY(=1)
THE DATA MEMBERS ARE CALLED THREAD PRIORITY MODIFIERS. THE
PURPOSE OF THREAD PRIORITY MAODIFIERS IS THAT WHICH THREDS TO
EXECUTE FIRST,SECOND AND LAST.
THE DEFAULT PRIORITY OS THE THREAD IS NORM_PRIORITY(=5)
CONSTRUCTORS:

Thread();
THIS CONSTRUCTOR IS USED FOR CREATING AN OBJECT OF THREAD CLASS
WITHOUT GIVING USER FRIENDLY NAME TO THE THREAD.IF WE CREATE NNUMBER OF OBJECTS WITH THIS CONSTRUCTOR THEN THEDEFAULT NAMES
OF THE THREAD STARTS WITH THREAD-0,THREAD-1....
GIVING THESE DEFAULT NAMES ARE NOT RECOMMEND TO GIVE USER
FRIENDLY NAMES TO THE THREAD
EG:- Thread t1=new Thread();
HERE T1 IS CALLED OBJECT/REFERRENCE VARIABLE AND WHOSE DDEFAULT
NAME IS "THREAD-0".
Thread(String);
Thread t!=new Thread("HARSHA");
THIS CONSTRUCTOR IS USED FOR CREATING AN OBJECT OF THREAD CLASS
BY TO GIVE USER FRIENDLY NAME TO THE THREAD.
Thread(Runnable);
Thread(Runnable,String);
INSTANCE METHODS:Public Final Void getName(String)
Public Final String getName()
THE ABOVE METHODS ARE USED FOR GETTING THE USER FRIENDLY NAME
TO THE THREAD AND GETTING THE NAME OF THE THREAD.
EG:-Thread t1=new Thread(0;
String tname=t1.getName();
sop(tname);//Thread -1
t1.getName("harsha");
tname=t1.getName();
sop(tname);//harsha

NOTE :-ANY METHOD STATS WITH GET***(---)THEN IT IT IS


CALLED_______MODIFIER AND WHOSE PURPOSE IS CHANGING THE VALUE OF
THE OBJECT.IF ANY METHOD STARTS WITHGET***()THEN IT IS KNOWN AS
INSPECTOR AND WHOSE PURPOSE IS TO OBTAINING THE VALUES FROM
OBJECT.
NOTE:-FINAL METHODS CAN'T BE OVERRIDDEN
Public Final Void getPriority(int);
Public Final Void getPriority();
THE ABOVE METHODS ARE USED FOR GETTING THE PRIORITY TO THREAD
AND GETTING PRIORITY OF THE THREAD.
EG:-Thread t1=new Thread("harsha");
int pv=t1.getPriority(0);
sop(pv);//s=>NORM_PRIORITY
Thread Priority(Thread MAX_PRIORITY)
pv=t1.getPriority();
sop(pv)//10=>MAX_PRIORITY
Public Final Boolean IsAlive():THIS METHOD RETURNS TRUE WHEN PROVIDED THE THREAD IS IN
READY,RUNNING AND WAITING STATES.IT RETURNS FALSE WHEN THE
THREAD IS NEW AND HALTED STATES
Public Void Run():IT IS ONE OF THE PREDEFINED NULL BODY METHOD PRESENT IN THREAD
CLASS.THIS METHOD IS ALWAYS FOR THE LOGIC OF THE JAVA PROGRAM
WHICH IS TO BE EXECUTED BY JVM.
Public Final Start():*WHEN WE CALL THIS METHOD UPON THE THREAD CLASS OBJECT,IT CAN
PERFORM 3 OPERATIONS
--IT MOVES THE THREAD FROM NEW STATE TO READY STATE.

---IT PROVIDES INTERNAL SERVICE OF MULTI


THREADING(CONCURRENTLY,SYNCHRONISATION,INTERTHREAD
COMMUNICATION) INTO THE THREAD CLASS OBJECT.
----IT AUTOMATICALLY CALLS OWN()WHICH IS CONTAINING THE LOGIC OF
THREAD
----HENCE TO DEVELOP ANY TBA,CHOOSE AN APPROPRIATE USER DEFINED
CLASS IT MUST EXTENDS JAVA.LANG.THREAD CLASS AND WE MUST
OVERWRITE NULL BODY RUN() OF THREAD CLASS
class Th1 extends Thread
{
Public Void Run()//overridden method
{
---____
____
}
Th1 t1=new Th1();
boolean b1=t1.IsAlive(0;
sop(t1)''false
b1=t1.IsAlive();
sop(b1);//true
*IT IS NOT RECOMMENDE TO THE JAVA PROGRAMMER TO CALL RUN()
DIRECTLY BECAUSE WE CANT GET THE MULTITHREADING SEVICES HENCE
RUN()MUST BE CALLED ALWAYS TO THROUGH START()
*Public Final Void Suspend():THIS METHOD USED FOR SUSPENDING THE CURRENTLY EXECUTING
THREADS WHEN WE CALL SUSPEND()UPON THE THREAD CLASS OBJECT,
WHOSE EXECUTION WIL BE TERMINATED,PLACE THE CURRENT EXECUTION
DETAILS IN THE PCB AND THREAD WILL BE ENTERED INTO WAITING STATE

T1.Suspend();
*Public Final Void Resume();THIS METHOS IS USED TO TRANSFERING THE SUSPENDED THREADS FROM
WITING STATE TO READY STATE WHEN THE THREADS ARE
RESUMED(RESTARTED)THEN THEY CONTINOUSTHEIR EXECUTION WHERE
THEY LEFT OFF BEFORE THEIR SUSPENSION.
T1.Resume();
*Public Final Void Stop():
THIS METHOD IS USED FOR TERMINATING /STOPS THE EXECUTION OF THE
THREAD. WHEN WE RESTART THE STOPPER THREADS THEY START
CONTAINING THEIR EXECUTION FROM THE BEGGINING
Public Final Void Join();THROWS JAVA.LANG.INTERRUPTED EXCEPTION THEIR
COMPI=LETION OF EXECUTION AS A SINGLE AND HAND OVER TO THE
GARBAGE COLLECTOR
THIS PROCESS WILL IMPROVE THE EFFICIENCY OF MULTI THREADDING APPS
*THE DEFAULT ENVIRONMENT OF MULTI THREADING SAYS INDIVIDUALLY
COLLECTING THE THREADS AND INDIVIDUALLYHAND OVERING TO THE
GARBAGE COLLECTOR WHICH IS ONE OF THE TIME CONSUMING PROCESS.
Join()THROWS A PRE-DEFINED EXCEPTION CALLED
JAVA.LANG.INTERRUPTTEDEXCEPTION--IT IS ONE OF THE UNCHECKED
EXCEPTION
WHEN INTERRUPTED EXCEPTION OCCUR:LET US ASSUME 'N'NO OF THREADS ARE CREATED STARTED ALL OF THEM
UNDER EXECUTION,(N-1)THREADS ARE COMPLETED THEIR EXECUTION AND
JOINED AND STILL,Nth THREAD IS UNDER EXECUTION.DUE TO MAIN MEMORY
MANAGMENT OF O.S THREAD GROUPNAME IS ATTEMPTING TO COLLECT ALL
THE THREADS EVEN THOUGH Nth THREAD IS UNDER EXECUTION,AT THIS
TIME OF THREAD WITH RESPECT TO Nth THREAD JVM GENERATES A PRE
DEFINED EXCEPTION CALLED JAVA.LANG.INTERRUPTEDEXCEPTION.
EG:try

{
t1.join();
t2.join();
:
tn.join();
}catch(InterruptedException ie)
{
sop("problem in tread line");
}
STATIC METHODS:static methods of thread class must be access with class name
Public Static Final Thread CurrentThread():
it isone of the factory method and it is used for finding name of the threads
which are default by meaning in java execution environment
eg:Thread t=Thread.CurrentThread();
sop(t);//Thread[Main,5,Main]----->[fgt,priority,tgn)
t1.getName("harsha");
sop(t);//[harsha,5,Main]
Public Static Final Void Sleep(lang)throws java.lang.InterruptedException
this method is used for making the currently executing thread to sleep for
aperiod of time interms of MS.once the sleep time of the thread is over it will
be automatically transferred into ready&running states .once the thread is
sleeping further operations will not be performed until the sleep time is over.
WHEN INTERRUPTEDEXCEPTION OCCURS:it is one of the un checked
exception,let us assume first thread of the current program sleeping in one of
the location of main memorymanagement of O.S,the second thread of same

program attempting to sleep in the same location when the first thread is
sleeping,wrto that thread .jvm generates a re defined exception called
java.lang.InterruptedException
eg:
try
{
=======
thread.sleep(1000)
=======
}catch(InterruptedException ie)
{
sop('problem in thread exception");
}
write a jp which will print preliminary info abt thread such as name of the
threads which are default running,whose execution status,name of the
defined programmersthread whose execution status head priority modifier
value?
ans://thdemo1.java
class Thdemo1
{
Public Static Void main(String k[]){
thread t1=thread.Current Thread();
sop("default name="+t1)//thread(main,5,main)
boolean state=t1.isAlive();
sop("execution status of t1="+state);//tree
Thread t2=new Thread();
//new thread

sop("default name of priority defnition FGT=t2.getName(0);


state =t2.isAlive();
sop("exe status of t2="+state);//false
sop("val of max priority="+Thread.MAX_PRIORITY);//0
sop('value of norm priority="+Thread.NORM_PRIORITY);
sop{val of min="+Th)
}
}
wajp which will print 1-10 numbers each and every sec.
//thdemo2.java
class th1 extends Thread
{
public void run(0
{
try
{
for(i=1;i<10;i++)
{
sop("value of i="+i);
Thread.sleep(1000);
}//for
}catch(InterruptedException ie)
{
sop("pb in thread");
}

}//run()
class thdemo1
{
psvm(String k[])
{
th1 t1=new th1();
sop("exe status of t1 before start="+t1.isAlive());
t1.start();
sop(exe status of t1 afterstart="+t1.is Alive());
try
{t1.join();
}catch(Interrupted Exception ie)
{
sop("pb in thread");
}
sop(exe status of t1 after com="+t1.isAlive())//false
}
}
THREAD SYNCHRONIZATION TECHNIQUES:we have 2 types of synchronizations techniques they are:---synchronized
instance method and synchronized static method.
SYNCHRONIZED INSTANCE METHOD:-when an ordinary instance method
accessed by multiple threads the we get inconsistent results.to avoid this
inconsistent result the defnition of ordinary instance method must be made
as synchronized.by using synchronized keyword
syn:-

synchronised ret.type methodname(list of formal parameters if any)


{
blockof stmt(s)-----blc
}
as long as thread is executing synchronized instance methods then object of
corresponding class will be locked
eg:class Amount
{
int sal=0;
synchronized void deposit(int amt)
{
bal=bal+amt;
sop(current bal="+bal);
}
}
as long as thread is executing the above synchronized instance deposit
method the jvm will lock an objecty of account class.
SYNCHRONIZED STATIC METHOD:If any order static method accessed by multiple threads concurrently then we
get inconsisten results ,to overcome this inconsistent results the defnition of
ordinary static method must be made as synchronized.by using synchronized
keyword
syn:synchronized static returntype methodname(list of formal parameters)
{
block of statement(s)

}
as long as thread is executing,synchronised static method then jvm will lock
the corresponding class
class Account
{
private int bal=0;
synchronized static void deposit(int amt)
{
bal=bal+amt;
sop("current sal="+bal);
}
as long as thread is executing the above synchronized static deposit method
hen jvm will lock account class
*hence the concept of synchronization also provides thread safety results..

Você também pode gostar