一些基础之一

高并发

面试的时候都喜欢问这个问题,解决高并发的问题根源在于解决高并发下共享资源的控制问题。也就牵扯到多线程下共享资源的同步问题。

  • 同步:单线程场景下,不需要考虑资源的同步,在执行一个方法或者操作后,一直等待结果,当然这时候可以有个超时的处理机制,但是本质上还是一直阻塞的。
  • 异步:多线程场景下,就需要考虑异步操作,也就是做一件事,不影响别的操作。在执行一个操作后,不去理会结果,而是去处理另外的操作,直到接收到已经处理完成的通知或消息,才去处理对应的结果。

解决并发和同步问题,主要是通过锁机制,不管是数据库级别,还是缓存级别,都是通过锁来完成。

  • 悲观锁,一般是数据库级别,也就是锁定对应的行级数据,优点是可以控制数据不出问题,缺点是性能方面
  • 乐观锁,一般通过采用version字段的方式来控制,不会锁定对应的数据,性能也比较高,但是会导致脏数据,比如发券场景下的超发现象,以及商品库存的超卖现象。
  • 对于单系统而言,在代码级别使用syncrinized来控制代码的访问是可行的,但是在分布式环境下,只能通过数据库锁或者缓存锁来控制。
  • 缓存锁的优势:速度相对DB是比较快,可以有效降低DB的压力。比如redis的watch,对应的jedis就需要使用setnx自己实现lock方法;比如tair在ldb的incr方法及put方法,incr方法指定lowBound和upBound(也就是一个取值范围)可以解决这个问题,而put方法则传入version版本来做,也是乐观锁。(参见:https://yq.aliyun.com/articles/58928
  • 当然数据库可以通过分库分表的方式来缓解压力,对于老数据可以考虑增加历史库,以保证数据量不会影响对应的数据库操作;而缓存也可以通过设置多个Key来分流单key的锁竞争压力。

设计模式 -- 后续每天补充

设计模式是代码设计经验的总结,在代码复用,稳定性以及易理解方面都有一定的保证。具体参见:
http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html

  • 设计模式的六大原则
    1、开闭原则(Open Close Principle)
    开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
    2、里氏代换原则(Liskov Substitution Principle)
    里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
    3、依赖倒转原则(Dependence Inversion Principle)
    这个是开闭原则的基础,针对接口编程,依赖于抽象而不依赖于具体
    4、接口隔离原则(Interface Segregation Principle)
    使用多个隔离的接口,比使用单个接口要好。降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
    5、迪米特法则(最少知道原则)(Demeter Principle)
    为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立
    6、合成复用原则(Composite Reuse Principle)
    原则是尽量使用合成/聚合的方式,而不是使用继承
工厂模式

实现同一个接口的对象,如果需要大量创建,则使用工厂模式。工厂模式又可以细分为普通工厂模式和静态工厂模式。以及为了解决上述工厂模式需要修改原有代码的抽象工厂模式

  • 接口及实现
    // interface
    public interface Sender { public void send();}
    //mailSender
    public class MailSender implements Sender { public void send() { System.out.println("Mail Sender"); }}
    // smsSender
    public class SmsSender implements Sender { public void send() { System.out.println("Sms Sender"); }}
  • 普通工厂模式:
    public class NormalSenderFactory {
    public Sender mailSender(){ return new MailSender(); }
    public Sender smsSender(){ return new SmsSender(); }
    }

  • 静态工厂模式
    public class StaticSenderFactory {
    public static Sender mailSender(){ return new MailSender(); }
    public static Sender smsSender(){ return new SmsSender(); }
    }

  • 调用方式
    public class SenderFactoryTest {
    public static void main(String[] args){
    NormalSenderFactory senderFactory = new NormalSenderFactory();
    senderFactory.mailSender().send();
    senderFactory.smsSender().send();
    // 静态工厂模式调用
    StaticSenderFactory.smsSender().send();
    StaticSenderFactory.mailSender().send(); }
    }

  • 抽象工厂模式
    工厂方法模式有一个问题就是,对象的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则。所以也就有了抽象工厂模式。
    抽象工厂模式增加一个新的接口,用于封装原有的工厂,也就是说可以创建不同的工厂来处理不同的业务。

  • 接口及实现
    //provider
    public interface Provider { public Sender produce();}
    // smsFactory
    public class SmsFactoryProvider implements Provider {
    public Sender produce() { return new SmsSender(); }
    }
    // mailFactory
    public class MailFactoryProvider implements Provider {
    public Sender produce() { return new MailSender(); }
    }
  • 调用方式
    public class AbstractFactoryTest {
    public static void main(String[] args){
    Provider provider = new SmsFactoryProvider(); provider.produce().send();
    }
    }
单例模式

保证只有一个对象存在,注意在多线程场景下,需要使用synchronized来锁住对应的instance,也就是需要用synchronized来锁定对应的对象
注意的是,采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同?

  • 首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的)
  • 其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。
  • 再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。
  • 最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!
建造者模式

相当于将多个工厂的调用放到一起,创建批量的不同子类型的复合体复杂对象,如下:

public class SenderBuilder {    
    private List<Sender> senderList = Lists.newArrayList();    

    public List<Sender> buildMail(int count){        
         for(int i=0;i<count;i++){            senderList.add(new MailSender());        }        
         return senderList;    
    }    

   public List<Sender> buildSms(int count){        
       for(int i=0;i<count;i++){            senderList.add(new SmsSender());        }        
       return senderList;    }
   }

 // test类
 public class BuilderTest {    
       public static void main(String[] args){        
          SenderBuilder senderBuilder = new SenderBuilder();        
          senderBuilder.buildMail(10);    
   }}
原型模式
适配器模式

将一种接口转换成另外一种接口,以消除接口不匹配造成的兼容性问题。

装饰模式

需要(动态)扩展一个类的功能,实现同一个接口,并且调用原有类,只不过在原有类对应方法的前后加入自己的业务处理逻辑。

代理模式

跟装饰模式其实很相似,都是去扩展一些原有类的功能,不过代理模式会隐藏掉原有类的对象及入口,而装饰模式不会。

外观模式

讲互相有依赖关系的对象,统一放入一个新的外观类中,已去除彼此间的依赖,降低耦合。类似于OrderTO中的bizOrder,payOrder以及logicOrder。

桥接模式

通过对Bridge类的调用,实现了对接口Sourceable的实现类SourceSub1和SourceSub2的调用


Paste_Image.png
组合模式

将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树

Paste_Image.png
享元模式

享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。

策略模式

策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。

模板模式

一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用

观察者模式

当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系

责任链模式

有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整

状态模式

根据状态的不同来实现不同的业务处理

HashMap的实现

HashMap基于数组+链表实现,其中数组是key值对应的hashcode,而链表则是对应的entry,entry是key-value的组合,根据key的hashcode决定存储在哪个位置对应的链表中。Entry还包含next属性,指向下一个entry对象。
在遍历hashMap时,如果需要remove某个位置的参数,要用iterator来remove,直接调用hashmap的remove方法会导致modCount变化,modCount不匹配时会报出ConcurrentModifitionException,导致remove失败。
key值的hashcode对应的链表需要去重排元素。

ConcurrentHashMap主要引入了segment,把整个hashmap分段加锁,来达到控制并发同时解决单一锁瓶颈的目的。segment继承了ReentrantLock,另一种锁机制。

Volatile

每个线程都有自己的线程栈空间,不存在共享资源的问题。
基础类型的变量存储在栈中,复杂对象的引用保存在线程栈中,而对应的对象则存储在堆中。
volatile只能修饰变量,而synchronized则可以修饰类、方法、代码块、变量,作用域是不同的

  • 针对基础类型

    • 对于没有使用volatile修饰的基础类型,每个线程在用到这个对象时,都会从主线程的栈空间中拷贝一份副本到本线程栈中,后面的每次操作都是操作这个副本。只有当线程结束时,会同步给主线程空间。
    • 而对于使用volatile修饰的基础类型,则每个线程操作的都是主线程栈中的变量,但是jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的,还是会存在并发问题。
  • 对于引用变量
    不管是否使用volatile,线程栈中保存的都是一个引用指针,保存的是堆中的内存地址,指向的是堆中的对象。所以这种情况下的读写操作,没办法保证是原子性的。

IO

阻塞IO
非阻塞IO
SELECTOR

concurrent包下的常用类
jvm,类加载
常见的代码,字符串,字符
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    RamboLI阅读 748评论 0 1
  • 2017.02.25 周六 阴 阅读这篇文章大概需要8分钟。 一 周末闲暇无事,橙子不知道去哪浪了,波波去修双学位...
    卢安克阅读 998评论 13 3
  • 其实很多选择自己的发展方向包括择偶标准都是价值观使然,也没有什么好遗憾的。最近在研究一本关于说话的书,挺有意思的。...
    六月花阅读 191评论 0 0