2.2.7 임의의 대상을 대상 모니터로 삼다

11496 단어
여러 라인이 같은 대상의 다른 이름의synchronized 동기화 방법이나synchronized(this) 동기화 코드 블록을 호출할 때 호출하는 효과는 순서대로 실행하는 것이다. 즉 동기화되고 막히는 것이다.이것은synchronized 동기화 방법이나synchronized(this) 동기화 코드 블록이 각각 두 가지 작용을 한다는 것을 설명한다.
  • synchronized 동기화 방법synchronized 동기화 방법 또는synchronized(this) 동기화 코드 블록 호출이 막힌 상태입니다.같은 시간에synchronized 동기화 방법의 코드만 실행할 수 있음
  • synchronized(this) 동기화 코드 블록이 다른synchronized 동기화 방법이나synchronized(this) 동기화 코드 블록에 대한 호출이 막힌 상태입니다. 같은 시간에 한 라인만 synchronized(this) 동기화 코드 블록의 코드
  • 를 실행할 수 있습니다.
    앞에서 학습한 바와 같이synchronized(this) 형식의 동기화 코드 블록을 사용하는데 사실 자바는'임의의 대상'을'대상 감청기'로 동기화하는 기능을 지원한다.이 '임의의 대상' 은 대부분 실례 변수와 방법의 매개 변수이며,synchronized (비this 대상) 형식을 사용합니다.
    앞에서 synchronized(this) 동기화 코드 블록의 역할에 대한 정리를 통해 알 수 있듯이synchronized(비this 대상) 형식의 역할은 1가지에 불과하다.synchronized(비this 대상 x) 동기화 코드 블록의 코드
    '대상 모니터' 를 같은 대상으로 가지고 있는 전제에서 같은 시간에 한 라인만synchronized (비this 대상 x) 동기화 코드 블록의 코드를 실행할 수 있습니다.
    /**
     * @author wuyoushan
     * @date 2017/4/10.
     */
    public class Service {
    
        private String usernameParam;
        private String passwordParam;
        private String anyString=new String();
    
        public void setUsernamePassword(String username,String password) {
            try{
                synchronized (anyString){
                    System.out.println(" :"+Thread.currentThread().getName()
                    +" "+System.currentTimeMillis()+" ");
                    usernameParam=username;
                    Thread.sleep(3000);
                    passwordParam=password;
                    System.out.println(" :"+Thread.currentThread().getName()
                    +" "+System.currentTimeMillis()+" ");
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/4/4.
     */
    public class ThreadA extends Thread{
    
        private Service service;
    
        public ThreadA(Service service){
            super();
            this.service=service;
        }
    
        @Override
        public void run() {
           service.setUsernamePassword("a","aa");
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/4/4.
     */
    public class ThreadB extends Thread{
    
        private Service service;
    
        public ThreadB(Service service){
            super();
            this.service=service;
        }
    
        @Override
        public void run() {
            service.setUsernamePassword("b","bb");
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/3/20.
     */
    public class Run {
        public static void main(String[] args){
            Service service=new Service();
            ThreadA a=new ThreadA(service);
            a.setName("A");
            a.start();
            ThreadB b=new ThreadB(service);
            b.setName("B");
            b.start();
        }
    }
    

    프로그램 실행 결과는 다음과 같습니다.
     :A 1492391031020 
     :A 1492391034020 
    username:a password:aa
     :B 1492391034020 
     :B 1492391037020 
    username:b password:bb
    

    자물쇠 비this 대상은 일정한 장점을 가진다. 만약에 한 종류에 많은synchronized 방법이 있다면 이것은 동기화를 실현할 수 있으나 막히기 때문에 운행 효율에 영향을 미친다.그러나 동기화 코드 블록 자물쇠가 this 대상이 아니라면synchronized(비this) 코드 블록의 프로그램과 동기화 방법은 비동기적이며 다른 자물쇠this 동기화 방법과 this 자물쇠를 다투지 않으면 운영 효율을 크게 높일 수 있다.
    서비스java 파일 코드는 다음과 같이 변경되었습니다.
    /**
     * @author wuyoushan
     * @date 2017/4/10.
     */
    public class Service {
    
        private String usernameParam;
        private String passwordParam;
    
        public void setUsernamePassword(String username,String password) {
            try{
                String anyString=new String();
                synchronized (anyString){
                    System.out.println(" :"+Thread.currentThread().getName()
                    +" "+System.currentTimeMillis()+" ");
                    usernameParam=username;
                    Thread.sleep(3000);
                    passwordParam=password;
                    System.out.println(" :"+Thread.currentThread().getName()
                    +" "+System.currentTimeMillis()+" ");
                     System.out.println("username:"+usernameParam+" password:"+passwordParam);
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    

    프로그램 실행 결과는 다음과 같습니다.
     :A 1492474468701 
     :B 1492474468702 
     :A 1492474471702 
    username:b password:aa
     :B 1492474471702 
    username:b password:bb
    

    "synchronized (비this 대상 x) 동기화 코드 블록"형식으로 동기화 작업을 할 때 대상 모니터는 같은 대상이어야 합니다.같은 대상 모니터가 아니라면 실행 결과가 비동기적으로 호출되면 교차 운행된다.
    다음은'synchronized(비this 대상 x) 동기화 코드 블록'형식을 사용할 때 서로 다른 대상 감청기를 가지고 있을 때 다른 효과가 있는지 다른 항목으로 검증해 보겠습니다.
    
    /**
     * @author wuyoushan
     * @date 2017/4/10.
     */
    public class Service {
        private String anyString=new String();
        public void a() {
            try{
                synchronized (anyString){
                    System.out.println("a begin");
                    Thread.sleep(3000);
                    System.out.println("a end");
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    
        synchronized public void b() {
            System.out.println("b begin");
            System.out.println("b end");
    
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/4/4.
     */
    public class ThreadA extends Thread{
    
        private Service service;
    
        public ThreadA(Service service){
            super();
            this.service=service;
        }
    
        @Override
        public void run() {
            service.a();
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/4/4.
     */
    public class ThreadB extends Thread{
    
        private Service service;
    
        public ThreadB(Service service){
            super();
            this.service=service;
        }
    
        @Override
        public void run() {
            service.b();
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/3/20.
     */
    public class Run {
        public static void main(String[] args){
            Service service=new Service();
            ThreadA a=new ThreadA(service);
            a.setName("A");
            a.start();
            ThreadB b=new ThreadB(service);
            b.setName("B");
            b.start();
        }
    }
    

    프로그램 실행 결과는 다음과 같습니다.
    a begin
    b begin
    b end
    a end
    

    대상 모니터가 다르기 때문에 실행 결과는 비동기적이다.동기화 코드 블록은 비동기화synchronized 방법에 놓고 설명할 수 있으며 호출 방법의 루틴 실행 동기화/순서성을 보장할 수 없다. 즉, 루틴 호출 방법의 순서는 무질서하다. 비록 동기화 코드 블록에서 실행되는 순서가 동기화되지만 이렇게 하면'더럽히기'문제가 발생하기 쉽다.
    'synchronized(비this 대상 x) 동기화 코드 블록'형식을 사용해도'더러운 읽기'문제를 해결할 수 있습니다.그러나 더러운 읽기 문제를 해결하기 전에 먼저 하나의 실험을 하고 실험의 목표는 여러 개의 라인이 같은 방법을 랜덤으로 호출하는 것을 검증하는 것이다.
    /**
     * @author wuyoushan
     * @date 2017/2/5.
     */
    public class MyList{
        private List list=new ArrayList();
        synchronized public void add(String username){
            System.out.println("ThreadName="+Thread.currentThread().getName()
                    +" add ");
            list.add(username);
            System.out.println("ThreadName="+Thread.currentThread().getName()
                    +" add ");
        }
        synchronized public int getSize(){
            System.out.println("ThreadName="+Thread.currentThread().getName()
                    +" getSize ");
            int sizeValue=list.size();
            System.out.println("ThreadName="+Thread.currentThread().getName()
                    +" getSize ");
            return sizeValue;
        }
    
    }
    
    /**
     * @author wuyoushan
     * @date 2017/2/5.
     */
    public class ThreadA extends Thread{
        private MyList list;
    
        public ThreadA( MyList list) {
            super();
            this.list = list;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                list.add("threadA"+(i+1));
            }
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/2/5.
     */
    public class ThreadB extends Thread {
        private MyList list;
    
        public ThreadB( MyList list) {
            super();
            this.list = list;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                list.add("threadA"+(i+1));
            }
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/2/5.
     */
    public class Run {
        public static void main(String[] args) {
            MyList myList=new MyList();
            ThreadA a=new ThreadA(myList);
            a.setName("A");
            a.start();
            ThreadB b=new ThreadB(myList);
            b.setName("B");
            b.start();
        }
    }
    

    프로그램이 실행된 결과는 다음과 같습니다.
    ThreadName=B add 
    ThreadName=B add 
    ThreadName=A add 
    ThreadName=A add 
    ThreadName=B add 
    ThreadName=B add 
    

    실행 결과를 보면 동기화 코드 블록의 코드는 동기화되어 인쇄되고 현재 라인의 '실행' 과 '종료' 는 쌍으로 나타납니다.그러나 스레드 A와 스레드 B의 집행은 비동기적이어서 더러운 읽기 환경이 나타날 수 있다.스레드 실행 방법의 순서가 확실하지 않기 때문에 A와 B 두 스레드가 지점 판단을 가진 방법을 실행할 때 논리적인 오류가 발생하고 더러운 읽기가 발생할 수 있다.
    /**
     * @author wuyoushan
     * @date 2017/4/19.
     */
    public class MyOneList {
        private List list=new ArrayList<>();
    
        synchronized public void add(String data){
            list.add(data);
        }
    
        synchronized public int getSzie(){
            return list.size();
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/4/19.
     */
    public class MyService {
        public MyOneList addServiceMethod(MyOneList list,String data){
            try{
                if(list.getSzie()<1){
                    Thread.sleep(2000);     // 2 
                    list.add(data);
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return list;
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/4/4.
     */
    public class ThreadA extends Thread{
        private MyOneList list;
    
        public ThreadA(MyOneList list){
            super();
            this.list=list;
        }
    
        @Override
        public void run() {
            MyService service=new MyService();
            service.addServiceMethod(list,"A");
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/4/4.
     */
    public class ThreadB extends Thread{
    
        private MyOneList list;
    
        public ThreadB(MyOneList list){
            super();
            this.list=list;
        }
    
        @Override
        public void run() {
            MyService service=new MyService();
            service.addServiceMethod(list,"B");
        }
    }
    
    /**
     * @author wuyoushan
     * @date 2017/3/20.
     */
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            MyOneList list=new MyOneList();
    
            ThreadA a=new ThreadA(list);
            a.setName("A");
            a.start();
            ThreadB b=new ThreadB(list);
            b.setName("B");
            b.start();
            Thread.sleep(6000);
            System.out.println("listSize="+list.getSzie());
        }
    }
    
    

    프로그램 실행 후 결과는 다음과 같습니다.
    listSize=2
    

    더러운 독서가 나타났다.두 라인이list 매개 변수의 크기 () 크기를 비동기적으로 되돌려주기 때문입니다.그 해결책은 My Service를 동기식으로 변경하는 것입니다.java 클래스 파일 코드:
    /**
     * @author wuyoushan
     * @date 2017/4/19.
     */
    public class MyService {
        public MyOneList addServiceMethod(MyOneList list,String data){
            try{
                synchronized (list) {
                    if (list.getSzie() < 1) {
                        Thread.sleep(2000);     // 2 
                        list.add(data);
                    }
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return list;
        }
    }
    
    

    list 매개 변수의 대상은 프로젝트에서 하나의 실례이고 하나의 예이기 때문에list 매개 변수의 getsize () 방법을 동기화해서 호출해야 하기 때문에list 매개 변수를 동기화 처리합니다.프로그램 실행 결과는 다음과 같습니다.
    listSize=1
    

    자바 다중 루틴 핵심 프로그래밍 기술 -2.2.7에서 발췌

    좋은 웹페이지 즐겨찾기