• 使用synchronized(非this对象)同步代码块解决脏读问题


    首先通过示例来学习验证多个线程调用同一个方法时随机的。

    package syn_out_asyn;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    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;
        }
    }
    package syn_out_asyn;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class ThreadA extends Thread {
        private MyList list;
        public ThreadA (MyList list){
            super();
            this.list = list;
        }
    
        public void run(){
            for(int i=0;i<10000;i++){
                list.add("ThreadA"+(i+1));
            }
        }
    }
    package syn_out_asyn;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class ThreadB extends Thread {
        private MyList list;
        public ThreadB(MyList list){
            super();
            this.list = list;
        }
        public void run(){
            for(int i=0;i<10000;i++){
                list.add("threadB"+(i+1));
            }
        }
    }
    package syn_out_asyn;
    
    /**
     * Created by Administrator on 2017/1/19 0019.
     */
    public class Run {
        public static void  main(String[] args){
            MyList myList = new MyList();
            ThreadA threadA =  new ThreadA(myList);
            threadA.setName("A");
            threadA.start();
            ThreadB threadB = new ThreadB(myList);
            threadB.setName("B");
            threadB.start();
        }
    }
    执行结果:
    ThreadName=A执行了add方法
    ThreadName=A退出了add方法
    ThreadName=A执行了add方法
    ThreadName=A退出了add方法
    ThreadName=A执行了add方法
    ThreadName=A退出了add方法
    ThreadName=B执行了add方法
    ThreadName=B退出了add方法
    ThreadName=B执行了add方法
    ThreadName=B退出了add方法
    ThreadName=B执行了add方法
    ThreadName=B退出了add方法

    从结果来看,同步块中的代码是同步打印的,当前线程的执行和退出时成对出现的。但线程A和线程B的执行却是异步的,这就有可能出现脏读的环境。由于线程执行的方法的顺序不确定,所以当A和B两个线程执行带有分之判断的方法时,就会出现逻辑上的错误,有可能出现脏读。

    package t9;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by Administrator on 2017/1/20 0020.
     */
    public class MyOneList {
        private List list  = new ArrayList();
        synchronized  public void add(String  data){
            list.add(data);
        }
        synchronized public  int getSize(){
            return list.size();
        }
    }
    package t9;
    
    /**
     * Created by Administrator on 2017/1/20 0020.
     */
    public class MyService {
        public MyOneList addServiceMethod(MyOneList list ,String data) {
            try {
                if (list.getSize() < 1) {
    
                    Thread.sleep(2000);//模拟从远程话费2秒取回数据
                    list.add(data);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
               return list;
        }
    }
    package t9;
    
    /**
     * Created by Administrator on 2017/1/20 0020.
     */
    public class MyThread1 extends Thread {
        private MyOneList list;
        public MyThread1(MyOneList list){
            super();
            this.list=list;
        }
        public void run(){
            MyService myService = new MyService();
            myService.addServiceMethod(list,"A");
        }
    }
    package t9;
    
    /**
     * Created by Administrator on 2017/1/20 0020.
     */
    public class MyThread2  extends Thread {
        private MyOneList list;
        public MyThread2(MyOneList list){
            super();
            this.list=list;
        }
        public  void run(){
            MyService myService = new MyService();
            myService.addServiceMethod(list,"B");
        }
    }
    package t9;
    
    /**
     * Created by Administrator on 2017/1/20 0020.
     */
    public class Run {
        public static  void main(String [] args) throws InterruptedException {
           MyOneList list = new MyOneList();
            MyThread1 thread1 = new MyThread1(list);
            thread1.setName("A");
            thread1.start();
            MyThread2 thread2 = new MyThread2(list);
            thread2.setName("B");
            thread2.start();
            Thread.sleep(6000);
            System.out.println("listSize="+list.getSize());
        }
    }
    运行结果:
    listSize=2

    脏读出现了,原因是两个线程以异步的方式返回list参数的size()大小,解决的办法就是同步化。

    修改MyService.java

    package t9;
    
    /**
     * Created by Administrator on 2017/1/20 0020.
     */
    public class MyService {
        public MyOneList addServiceMethod(MyOneList list ,String data) {
            try {
                synchronized (list) {
                    if (list.getSize() < 1) {
    
                        Thread.sleep(2000);//模拟从远程话费2秒取回数据
                        list.add(data);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
               return list;
        }
    }
    运行结果:
    listSize=1

    由于list参数对象在项目中是一份实例,是单例的,而且也正需要对list参数的getSize()方法做同步的调用,所以就对list参数进行同步处理。

    结论:synchronized(非this对象x):格式的写法是将x对象本身作为“对象监视器”

  • 相关阅读:
    Python开发——数据类型【字典】
    Python开发——数据类型【元祖】
    Python开发——数据类型【列表】
    Python开发——基础
    Python开发——数据类型【运算符】
    c#中IList<T>与List<T>
    观察者模式(Observer Pattern)
    中介者模式(Mediator Pattern)
    策略模式(Strategy Pattern)
    命令模式
  • 原文地址:https://www.cnblogs.com/dream-to-pku/p/6308620.html
Copyright © 2020-2023  润新知