zoukankan      html  css  js  c++  java
  • 【JAVA并发编程实战】2、对象的组合

    1、 设计线程安全的类

    1、找出构成对象状态的所有变量

    2、找出约束状态变量的不变性条件

    3、建立对象状态的并发访问管理策略

    package cn.xf.cp.ch04;
    
    /**
     * 
     *功能:JAVA监视器模式的线程安全计数器
     *时间:下午6:22:23
     *文件:Counter.java 
     *@author Administrator
     *
     */
    public class Counter
    {
        //只有这一个变量,这个value就是counter的全部状态
        private long value = 0;
        
        //获取值,单线程操作
        private synchronized long getValue()
        {
            return value;
        }
        
        public synchronized long increment()
        {
            if(value == Long.MAX_VALUE)
                throw new IllegalStateException("统计数值溢出");
            return ++value;
        }
    }

    2、实例封闭

    将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时总能持有正确的锁。

    通过封闭与加锁等机制使一个类成为线程安全的

    package cn.xf.cp.ch04;
    
    public class Person
    {
        private String name;
        private int age;
        private char sex;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        public char getSex()
        {
            return sex;
        }
        public void setSex(char sex)
        {
            this.sex = sex;
        }
        
    }
    package cn.xf.cp.ch04;
    
    import java.util.HashSet;
    import java.util.Set;
    
    public class PersonSet
    {
        private final Set<Person> mySet = new HashSet<Person>();
        
        public synchronized void addPerson(Person p)
        {
            mySet.add(p);
        }
        
        public synchronized boolean containsPerson(Person p)
        {
            return mySet.contains(p);
        }
    }

    2、1  Java监视器模式

    这个模式的对象会把所有可变状态都封装起来,并由对象自己的内置锁来保护。

    package cn.xf.cp.ch04;
    
    /**
     * 
     *功能:私有锁的使用
     *时间:下午9:18:01
     *文件:PrivateLock.java 
     *@author Administrator
     *
     */
    public class PrivateLock
    {
        //使用私有变量作为对象锁
        private final Object myLock = new Object();
        private int i;
        
        public void someMethod()
        {
            synchronized(myLock)
            {
                //这里对状态量i进行操作
                i = 110;
                System.out.println("私有锁");
            }
        }
    }

    私有的锁对象可以将锁封装起来,使客户代码无法获取锁,但是客户代码可以通过公有方法来访问锁,这样也就可以参与到同步中来。

    活跃性的问题:死锁, 饥饿和活锁

    饥饿(Starvation) 
       它描述了这样一个场景,当一个线程不能获取定期访问来共享资源而不能继续运行,在共享资源被饥渴线程长期占有时,就会发生饥饿。例如,加速一个对象提供一个要花很长时间才能返回结果的同步方法,如果一个线程频繁调用这个方法,其它线程也需要频繁调用同步进入同一个对象的方法时,阻塞就发生了。

       活锁(Livelock) 
       一个线程经常对另外一个线程的响应做响应的处理,如果线程的另外一个动作同样是对另外一个线程响应而发生,结果可能导致活锁,类似死锁,发生活锁的线程不能更进一步的处理,然而,线程并没有被阻塞,他们只是忙碌于响应对方而重复工作,这类似于两个人在走廊中试图让对方,a移向左以让b通过,而b移向右以让a通过,可以看到,他们仍然互相阻塞,a移动到右边,而b移动到左边,结果他们仍然还是阻塞着。。。

    如果不使用私有锁:那么可能客户代码错误地获取另一个对象的锁,可能会产生活跃性的问题(一个并发应用能够及时执行任务的特性称为活跃性)。此外想要验证某个公有访问的锁在程序中是否被正确地使用,则需要检查整个程序,而不是单个类。

       

    2、2 示例:车辆追踪

    车辆标识和位置点,类型

    package cn.xf.cp.ch04;
    
    public class MutablePoint
    {
        private int x, y;
        
        public MutablePoint()
        {
            x = 0;
            y = 0;
        }
        
        public MutablePoint(MutablePoint p)
        {
            this.x = p.getX();
            this.y = p.getY();
        }
    
        public synchronized int getX()
        {
            return x;
        }
    
        public synchronized void setX(int x)
        {
            this.x = x;
        }
    
        public synchronized int getY()
        {
            return y;
        }
    
        public synchronized void setY(int y)
        {
            this.y = y;
        }
    }

    车辆追踪类

    package cn.xf.cp.ch04;
    
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 
     *功能:基于监视器模式的车辆追踪
     *时间:下午9:50:12
     *文件:MonitorVehicleTracker.java 
     *@author Administrator
     *
     */
    public class MonitorVehicleTracker
    {
        private final Map<String, MutablePoint> locations;
        
        //构造函数对map进行初始化
        public MonitorVehicleTracker(Map<String, MutablePoint> locations)
        {
            //为了保持内部数据不会发生逸出,进行深拷贝
            this.locations = deepCopy(locations);
        }
        
        public synchronized Map<String, MutablePoint> getLocations()
        {
            return deepCopy(locations);
        }
        
        public synchronized MutablePoint getLocation(String id)
        {
            //获取要返回的数据
            MutablePoint loc = locations.get(id);
            //创建一个新的对象返回
            return loc == null ? null : new MutablePoint(loc);
        }
        
        public synchronized void setLocation(String id, int x, int y)
        {
            MutablePoint loc = locations.get(id);
            if(loc == null)
            {
                //如果没有这个对象的话,抛出异常,还是重新创建,看个人业务
                throw new IllegalArgumentException("没有这个id:" + id);
            }
            loc.setX(x);
            loc.setY(y);
        }
        
        private static Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> m)
        {
            //创建一个新的接受数据对象
            Map<String, MutablePoint> result = new HashMap<String, MutablePoint>();
            //循环取数据
            for(String id : m.keySet())
            {
                //根据key取值
                result.put(id, m.get(id));
            }
            
            //返回数据,返回指定映射的不可修改视图。
            //此方法允许模块为用户提供对内部映射的“只读”访问
            return Collections.unmodifiableMap(result);
        }
    }
  • 相关阅读:
    检查你的iOS程序是否正在被调试
    破解从 AppStore 下载的 IPA
    在 iOS 中如何发短信
    关于移动应用UI部分管理的一些思考
    在 iOS 应用中实现飞行模式提醒
    如何在iOS应用中拨打电话,并让用户确认
    [转]How to hide inputAccessoryView without dismissing keyboard
    php 读取文件并以文件方式下载
    一个session,判断用户唯一的技巧
    一个简单文件上传代码
  • 原文地址:https://www.cnblogs.com/cutter-point/p/5991205.html
Copyright © 2011-2022 走看看