|
SSISO Community검색 |
|
SSISO Community메뉴 |
|
SSISO Community카페 |
|
블로그 카테고리 |
|
|
Synchronized로 검색한 결과 |
|
등록일:2008-03-03 10:35:01 작성자: 제목:Synchronized(동기화) |
|
1. Modifier(메소드)
run메소드를 동기화 시킨다.
=> public Synchronized void run(){
//내용
}
2. 코드 블럭
코드의 일부분에 동기화 시킨다.
=> Synchronized(this) {
//this => 현재 클래스의 멤버 변수들에 대한 동기화가 보장된다.
//오브젝트(Object o)가 와야한다.(프로그램에서 사용하고 있는 객체를 주면된다.)
//내용
}
LOCK Flag = > 잠금 부분을 열수 있는 키와 같다.
LOCK Pool = > 스래드가 락을 사용하고 있으면 이부분에서 기다린다.
스레드로 하여 코드와 변수를 공유하는 코드 한객체변수로 2개의 스래드를 생성하고 1~10까지의 숫자를 공유한다. 하나의 객체를 생성하고 그것을 두개의 스래드로 객체를 생성해도 스래드는 각각의 스택을 갖고 그 저장장소에 지역변수를 저장하므로 각자의 스래드의 실행결과를 확인 할 수 있을것이다. 하지만 문제가 되는것은 인스턴스 변수로 선언할때 이것은 HEAP영역에 저장되기에 코드와 변수를 함께 공유하게 되는것이다. 이것은 같은숫자가 두번 찍히는 이상한 결과를 가져오게 되는데 오늘은 이것의 문제점에 대해 알아보고 Synchronized에 대하여 알아보도록 하겠다.
class ThreadEx1 implements Runnable {
int i=1;
public void run(){
for(;i<=10;i++){
System.out.println(i);
try{
Thread.sleep(20);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
}
class MyThread1{ //메인은 항상 같으므로 처음에만 한번 만들겠다.
public static void main(String[] args) {
ThreadEx1 te = new ThreadEx1();
Thread t1 = new Thread(te);
Thread t2 = new Thread(te);
/*
Thread t1 = new Thread(te,"A");
Thread t2 = new Thread(te,"B");
//Thread(ThreadGroup group, String name)
// Allocates a new Thread object.
//te의 객체에 "A"와 "B"라는 이름을 갖는 스래드를 생성한다.
*/
t1.start();
t2.start();
}
}
여 기에 Synchronized라는 키워드를 사용할 것인데 t1이라는 스래드가 실행되고 있을때, t2라는 스래드가 동시에 실행되지 않도록하는 역할을 한다. 이것의 사용은 메소드와 코드내 블록으로 사용할수 있다. 우선 메소드에 선언하는것을 알아보도록 한다. 오버라이드 하는 run()메소드에서 해보면...public Synchronized void run(){} 으로 선언한다. 아래예제의 결과를 보면... t1스래드가 시작되어 run()메소드를 실행하는데 동기화 메소드이므로 t1스래드가 실행되면 t2스래드는 t1스래드가 끝날때까지 Lock Pool이라는 곳에서 기다리게된다. t1스래드가 끝나고 t2스래드가 시작되면 인스턴스변수의값이 10이 초과되었으므로 더이상 실행되지 않는것을 확인할 수 있을 것이다. 코드 블록내에 Synchronized 사용가능하다.
public void run(){
Synchronized(this){
for(;i<=10;i++){
System.out.println(i);
try{
Thread.sleep(20);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
}
이렇게 사용가능하며 코드블록 동기할때 Synchronized( ) 이 괄호사이에 Object값을 넣어줘야 한다. 그래서 this를 사용하였다. 여기서 this는 현재 클래스 멤버 변수들에 대한 동기화가 보장된다.
class ThreadEx1 implements Runnable {
int i=1;
/*public Synchronized void run(){
for(;i<=10;i++){
System.out.println(i);
try{
Thread.sleep(20);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}*/
public void run(){
Synchronized(this){
for(;i<=10;i++){
System.out.println(i);
try{
Thread.sleep(20);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
}
}
이번에는 Thread생성자를 이용하여 현재스래드의 상태와 그 이름을 출력해보도록 하겠다.
Thread 생성자 api를 참고하고 메소드 summary중 currentThread()와 getName()를 참고한다.
class ThreadEx1 implements Runnable {
int i=1;
public void run(){
Synchronized(this){
String name = Thread.currentThread().getName();
//API문서를 참고하자! ,현재 사용중인 스래드 객체의 참조를 반환한다().스래드의 이름을 리턴한다()
for(;i<=10;i++){
System.out.println(i);
try{
Thread.sleep(20);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
}
}
이번에는 스래드의 이름이 "A"이고 50보다 작으면 스래드를 쉬게하고(sleep) 50과 100사이에서는 "A"스래드와 "B"스래드가 같이 출력되는 프로그램을 만들어 보겠다. 여기서 주의할점은 synchronizer블록 내에서 sleep()를 사용하지 않아야 한다는 점이다.아래예제의 출력결과를 보면 [A는 50이 넘어도 찍히지 않는다. B만계속 찍힌다.-else블록하면] || [하지않으면 - A와B가 순서없이 뒤죽박죽 출력된다.) 이것은 동기화 블록내에서 스래드를 sleep하게 하면 LOCK Flag를 반환하지 않고 쉬게 되므로 A는 계속 잠들어있게되는 것이다.
class ThreadEx1 implements Runnable {
int i=1;
public void run(){
while(i<=100){
Synchronized(this){
String name = Thread.currentThread().getName();
//API문서를 참고하자! ,현재 사용중인 스래드 객체의 참조를 반환한다().스래드의 이름을 리턴한다()
if(name.equals("A") ) {
if(i < 50){
try{
Thread.sleep(20);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
else{ //하지 않으면 뒤죽박죽 출력된다.
System.out.println(name+":"+i);
i++;
}
}
}
}
}
위 의 예제에서 문자점이었던 "A"스래드... sleep()은 동기화 에서 사용하지 않고 wait()를 사용함으로써 해결할수 있다. 기다린다는 메소드 java.lang.Object의 api문서를 참고하자. 또 여기서 문제점은 기다리게 한다면 그것을 불러줘야 다시 사용할 수 있다는 점이다. 그래서 wait는 notify(),notifyAll()과 같이 사용되어야 한다. 아래의 예제를 보도록 하자.
class ThreadEx1 implements Runnable {
int i=1;
public void run(){
while(i<=100){
Synchronized(this){
String name = Thread.currentThread().getName();
//API문서를 참고하자! ,현재 사용중인 스래드 객체의 참조를 반환한다().스래드의 이름을 리턴한다()
if(name.equals("A") ) {
if(i < 50){
try{
wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
else{ //하지 않으면 뒤죽박죽 출력된다.
System.out.println(name+":"+i);
i++;
if(i>50)
notify();
}
}
}
}
}
Synchronized
wait()
nofity()
notifyall()
Thread life cycle
동기화
스레드들이 공유하고 있는 자원에 대한 권한을 얻은 스레드만이 어떤 작업을 수행할 수 있도록
하는 것을 동기화(syncronzation)라고 한다.
동기화 블록
동기화 블록은 어떤 객체의 모니터(monitor)를 가지고 있는 스레드가 실행 권한을 획득하게 하는 방법이다. 모니터는 자바의 모든 객체가 가지고 있는 동기화 보호 객체로 객체에 대한 권한 정도라고 보면된다.
블록의 형식
Synchronized(someObject){
[코드]
}
동기화 메소드
동기화 블록은 블록 안의 코드만을 동기화하는 반면에 동기화 메소드는 메소드 전체를
동기화한다.
메소드의 형식
Synchronized void f(){
[코드]
}
동기화 메소드를 동기화 블록으로...
void f(){
Synchronized(this){
[코드];
}
}
쓰레드를 기다리게 하는 메소드로 wait()이 있고, 기다리고 있는 스레드에게 알리는 메소드로는 notify()가 있다. 그런데 특이한 점은 wait()과 notify()는 Thread 클래스의 멤버가 아니고 Object 클래스의 멤버라는 것이다. 사실 기다리거나 알리는 것도 객체의 모니터를 이용하는 것이기 때문이다.
wait()을 호출하는 코드 조각이다.
Synchronized(key){ // x1
...
try{
if(조건)key.wait(); // x2
}catch(InterruptedException ie){}
...
}
notify()는 대기 중인 스레드에게 알려서 깨우는 기능을 한다. 다음의 notify()를 호출하는 코드 조각이다
Synchronized(key){ // x1
...
key.notify(); // x2
...
}
notifyall()은 다수의 스래드가 실행중일때 모든 스래드를 깨워서 알리는 기능을 하는데
문제점을 발견할수 있을것이다. 이것은 코드를 하나더 작성하여 비교해준뒤
실행하면 문제를 해결할수 있다...
출처 Synchronized(동기화)|작성자 에스케이
|
|
|
|
|
|