当前位置: 首页 > news >正文

驻马店住房和城乡建设厅网站ppt模板免费网

驻马店住房和城乡建设厅网站,ppt模板免费网,网站的规划建设与分析,建筑公司组织架构一.单例模式——经典的设计模式 什么是单例模式#xff1a;就是规定一个类只能创建一个对象#xff0c;也就是保证某个类在程序中只存在唯一一个实例#xff0c;而不会创建出多个实例 根据对象创建的时机不同#xff0c;可以分为饿汉模式和懒汉模式 1.饿汉模式 在类加载…一.单例模式——经典的设计模式 什么是单例模式就是规定一个类只能创建一个对象也就是保证某个类在程序中只存在唯一一个实例而不会创建出多个实例 根据对象创建的时机不同可以分为饿汉模式和懒汉模式 1.饿汉模式 在类加载时就创建好那唯一一个对象 这样可以获得instance这个实例吗 显然如果代码这样写要想获得这个实例就得先创建一个对象然后调用getInstance方法这样的话就不是单例模式了所以应该将此方法设定为static方法直接用类来调用 可是这样的话我要是想再创建一个对象还是能够创建出来那该怎么办把构造方法设为private 这就是完整的饿汉模式了 线程安全问题考虑 饿汉模式是否会涉及到线程安全问题呢考虑一下如果多个线程调用getInstance就会又多个cpu读取内存的过程这个过程中没人修改的了该instance的指向所以就不会涉及到线程安全问题 2.懒汉模式 懒汉模式就是类加载时不急着创建对象而是在随时要用时才去创建对象 注意instance还得是static修饰的只不过不分配内存省下了创建实例的开销。 线程安全问题考虑 懒汉模式会涉及到线程安全问题吗答案是会涉及到当多个线程同时调用getInstance时起初都判断instance为空所以都去修改instance指向了这样每个线程得到的地址就会不一样但最终instance只有一个正确的指向。那么如何修改呢 懒汉模式的多线程版本 保证代码原子性 上面谈到了多个线程调用时可能出现误判的情况这是因为if的判断和new操作不是原子的所以我们应该给该操作加锁 这样可以吗可以的这里的locker是static的也就是说一个类只有一份可以保证不同的线程是对同一个对象加锁。但是这样写的话就违背了懒汉模式的初衷了这样写就又是在类加载时就创建了一个对象又不能省下开销了所以该怎么弄锁对象呢用反射通过反射来创建该类的对象对该类的实例进行加锁: 注意反射创建的对象可不是SingleTonLazy类的而是Class类的所以没有违背单例模式。 也可以写为 降低锁竞争的频率 如上这样写代码就会出现一个问题只要每次一调用getInstance就必须得先上锁再去判断是否要new然后还会有锁竞争开销特别大。但其实只有第一个创建instance时才会涉及到线程安全问题以后都回不去修改instance的指向就不会有线程安全问题就没必要加锁了。所以我们可以先判断一下是否为空如果为空就可能需要new就可能有线程安全问题就得加锁如果不为空就不涉及到线程安全问题就没必要加锁。所以代码修改如下 解决编译器优化导致的指令重排序问题 这里一谈到多线程就不得不考虑编译器为例提高效率而做出的优化操作在单线程模式下编译器锁做出的逻辑判断不会出错这时为了提高效率而对代码的执行顺序做出的修改也不会出错但是多线程下由于看不到另一个现成的工作所以优化可能会出错。 我们知道new操作是分为三步进行的这就可能会触发指令重排序的优化。new操作的三步为 1.申请内存空间 2.在内存上构造对象 3.把内存地址赋给instance引用 这里可能会有指令重排序从123变成132.在单线程模式下没问题但在多线程模式下就有问题了132的话第一个线程的对象还没new出来就把地址给了instance这导致第二个线程一位已经有了对象直接返回了instance就有可能在线程1执行第三步之前将instance返回导致拿到了未初始化的非法对象并去访问它的属性导致出错 所以要想办法不进行指令重排序所以给instance加上volatile 最终代码如下 3.总结 1.instance应该是static修饰的 2.构造方法设为private 3.getInstance设为static保证可以用类调用该方法 4.饿汉模式不涉及到线程安全问题 5.懒汉模式涉及到线程安全问题解决方案加锁在加锁之前判断避免反复加锁使用volatile避免指令重排序 二.阻塞队列 阻塞队列是一种特殊的队列也遵循先进先出的原则。与普通队列不同的是它是一种线程安全的数据结构有以下阻塞特性 1.当队列为满时继续入队列就会触发阻塞直到有其他线程从队列中出去 2.当队列为空时继续出队列就会触发阻塞知道有其他线程进入队列 该阻塞队列的意义就是实现生产者消费者模型 1.什么是生产者消费者模型 生产者将生产的产品放到仓库中消费者就从仓库中取产品。当产品放满仓库时就会阻塞等待停止生产直到有顾客开始取产品当消费者把产品取完时消费者就开始等直到生产者生产出产品 生产者消费者模型的优点一解耦合 耦合描述的是俩个模块之间的联系程度解耦合就是说俩个模块之间的想和影响变小了 例如现在有服务器A和服务器B配合进行工作A接收到了客户端发出的请求A把请求发给了BB再把响应返回给A此时若B出现了问题A就也会受影响若要再天哥服务器C代替B的工作A这边的代码就得改动还是会收到影响所以说此时AB的耦合程度就高 但要是A和B 不直接交互而是通过一个队列来交互A把任务放到队列中B从队列中拿取任务。当队列中任务满时A就不再接任务直到B把任务处理当队列中空时B就不再处理任务直到A接到了任务而当B出现问题时A也不会受影响此时再添加一个服务器C就可以也不用去修改A的代码因为ABC都是在对队列进行操作三者不会互相影响这就达到了解耦合的效果 生产者消费者模型的优点二削峰填谷 还是上面服务器AB的例子 如果没有阻塞队列那么每个A收到的请求都会立即反映给B也就是说A这边扛多少请求量B就得快速处理多少请求量。但是不同的服务器做的工作不同A比较轻松但B的工作量较大AB虽然访问量相同但消耗的硬件资源不同可能A可以承受得了这些并发量但B就可能会挂了就比如B要操作数据库而数据库就是一个分布式系统中相对脆弱的环节。 但要是有了阻塞队列B就不需要跟着A的节奏去处理数据了它可以依然按着自己的节奏慢慢来虽然速度慢了但不会把B搞挂了。 与其把B搞挂不如让它慢慢来。A得到的响应慢但总好过没有响应。 上述峰值情况不会已知存在当过了峰值后A的请求量就会主键回复正常B就有时间取慢慢处理纪颜的数据了这就是填谷 削峰填谷就可以保证突发情况下整个服务系统可以正常运行 2.自己实现阻塞队列 阻塞队列的关键是在普通队列的前提下加上线程安全以及阻塞。我们就用环形数组实现阻塞队列其实就是之前讲的循环队列head指向对头tail指向队尾从对头删除元素从队尾添加元素head和tail包含head不包含tail之间就是存放元素的空间 put向队尾添加元素 take从队首拿取元素 现在我们已经把put和take的雏形写好了但是没有人唤醒线程。谁去唤醒呢对于put来说应该是take来唤醒而对于take来说应该是put来唤醒 所以在每个方法的最后都应该加一个notifyAll方法 注意这里最好用notifyAll方法要是用notify方法就只能唤醒一个生产者或一个消费者其他人就永远无法被唤醒了 还有一个问题对于put方法来说一个线程被唤醒后队列一定不满吗不一定可能在唤醒到blocked的过程中又有其他线程把队列放满了所以应该在唤醒后再添加一个if判断如果还满着就得再锁上 但是每次出了wait就得再判断一次那这代码不就是无数个判断吗所以直接用while循环即可 同理take方法可以改写为 如何使用阻塞队列呢 3.标准库中的阻塞队列——BlockingQueue BlockingQueue是一个接口它的实现类有ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueue它继承自Queue这个接口所以它也有polloffer等方法但不建议使用因为这些方法无阻塞特性。而建议用puttake方法这些方法有阻塞特性阻塞式入队列阻塞式出队列但没有阻塞式获取队首元素等方法。 使用方法和上面我们自己实现阻塞队列是一样的 三.定时器 就是达到了某个设定的时间后就执行某个代码。防止出现死等现象比如客户端发出请求但服务器迟迟不响应。是请求没发出去还是服务器出现问题了不知道不可以死等 1.标准库中的定时器 标准克重有一个Timer类其中有一个核心方法schedule shedule包含俩个参数第一个参数指定列即将执行的代码第二个参数指定多长时间后执行 使用如下 实际上主线程执行schedule的时候就是把该任务给放到了timer对象中timer对象里面也有一个线程叫做扫描线程时间一到扫描线程就会执行。同时一个timer可以安排多个任务 2.自己实现定时器 首先timer中要有一个扫描线程用于扫描轮到了哪个线程执行其次要有一个数据结构来存放即将执行的任务最后还需要有一个类来描述要执行的任务 首先来想一想应该用什么数据结构呢如果用ArrayList就得不停地遍历数组来判断到哪个任务执行到时间了会很麻烦所以应该用一个有顺序的也就是优先级队列把时间最小的放在队首这就可用O(1)的时间来回去到时间最小的任务了 首先是一个描述任务的类 该类描述了这个任务的具体内容以及它的延迟时间。注意它最终要放到优先级队列中所以就应该是可以比较的也就是要实现comparable接口注意compareTo方法要进行强制类型转换 然后来看Timer类 首先有一个优先级队列然后提供一个schedule方法负责将任务入队列然后我们要搞一个扫描线程而且一个类只需要一个线程进行扫描这可以在构造方法中进行 如图在线程中进行循环扫描队首元素的操作。这里为什么要加锁主要有以下俩个原因首先在该线程中会用到wait操作其次这个扫描线程操作的是优先级队列而刚刚写到schedule方法也是在操作优先级队列所以不同线程操作同一个变量就会有线程安全问题所以也要加锁 然后一上来就是判断是否为空如果队列为空我们应该咋办呢那就等到队列不空为止。这里就和阻塞队列一样用while比反复用if更好更保险 然后看一下队首元素是否达到了执行时间如果达到了就调用它的run方法并且将它从队列中删除如果没达到就什么也不执行进入下一轮的whlie 这里的else还可以继续优化一下如果什么也不干就会反复进行以上判断直到到了规定的执行时间在这段时间中虽然任务没有执行但cpu也没有停下工作还是有很大的消耗。所以应该改一下else让它wait一段时间之后再进行下一轮判断这段时间就是将要执行任务的时间减去系统时间代码如下 这里就可以看出来为什么不用PriorityBlockingQueue而使用普通的优先级队列了就是因为我们要处理两个wait而阻塞队列很难实现唤醒两处等待 所以最终的代码如下 class MyTimerTask implements ComparableMyTimerTask{//任务执行的时间点private long time;//要执行的任务private Runnable task;public MyTimerTask(Runnable run,long delay){this.taskrun;this.timedelaySystem.currentTimeMillis();}Overridepublic int compareTo(MyTimerTask o) {return (int)(this.time-o.time);}public void run(){this.task.run();}public long getTime() {return time;}public Runnable getTask() {return task;} } class MyTimer{//使用一个数据结构来安排所有的对象private PriorityQueueMyTimerTask qnew PriorityQueue();//把要完成的任务构造成一个对象添加到优先级队列中public void schedule(Runnable run,long delay){MyTimerTask tasknew MyTimerTask(run,delay);q.offer(task);locker.notify();//唤醒扫描线程}//需要一个锁对象进行加锁操作private Object lockernew Object();public MyTimer(){Thread tnew Thread(()-{//循环进行多轮对队首元素的判定while(true){synchronized (locker){//循环等待直到队列不空为止while(q.isEmpty()){try {locker.wait();//这里的等待是因为队列为空所以它需要用schedule来唤醒} catch (InterruptedException e) {e.printStackTrace();}}MyTimerTask taskq.peek();if(task.getTime()System.currentTimeMillis()){task.run();//任务执行完了就应该从队列中删除q.poll();}else{//等待一段时间避免出现忙等消耗cpu资源的现象try {locker.wait(task.getTime()-System.currentTimeMillis());} catch (InterruptedException e) {throw new RuntimeException(e);}}}}});t.start();}} 四.线程池 为什么要有线程池首先有线程是因为进程太重量了但是要是线程太多不断地创建销毁线程也会导致开销加大也就从轻量变成重量了。那么该如何解决 一个是使用协程它是把系统调度过程省略了但java中协程并不流行另一个办法就是使用线程池它可以使线程不至于很慢 线程池的原理就是在使用线程1的时候就提前把线程2345……都创建好。优化了频繁创建销毁线程的场景 1.标准库中的线程池 标准库中实例化线程池对象用到不是构造方法而是其他类的一个普通成员方法。这种构造对象的模式叫做工厂模式 工厂模式 一般情况下通过new来创建对象new就会触发类的构造方法但是构造方法会有局限性就比如要创建一个点坐标有俩中创建模式 public Point(double x,double y)这是通过直角坐标系来创建 public Point(double r,double a)这是通过极坐标的形式来创建 但是这俩种方法没有构成重载因为参数类型都一样。这就是构造方法的局限性。但要是使用了普通方法就可以根据方法名称来区分构造形式这就是工厂模式。事件中就可以撞门搞一个PointFactory类里面编写makePointXY方法和makePointRA方法来进行区分 Executors创建线程池的几种形式 第一种是创建一个固定线程数量的线程池 创建一个只包含单个线程的线程池 创建一个线程数目动态增长的线程池。它会随着往池中加入任务会根据需要自动创建线程并且不会立即销毁 创建一个线程池可以将任务的调度放在给定的延迟时间之后。 由上面的源码可以看出Executors实际上是ThreadPoolExcutor的工厂它是对ThreadPoolExecutor的封装。executor表示执行者。 ThreadPoolExecutor的相关方法 构造方法 先来说一说corePoolSize和maximumPoolSize说这个之前我们来举个例子在一个大厂中包含了正式员工和实习生尬场为啥要招实习生呢就是因为任务太多了做不过来所以要招实习生。但是正式员工可以摸鱼也就是可以没事干闲着而实习生不可以摸鱼也就是说当任务量逐渐减少时实习生们就没事干了就会进行裁员裁的就是那些摸鱼实习生。线程池也是这样corePoolSize就是正式员工的数量它们永远不会被裁员maximumPoolSize就是正式员工加实习生的数量也就是线程池最大的容量。 keepAliveTime就是允许实习生摸鱼的时间当达到上限时这些线程就会被销毁 unit是时间的单位 workQueue这是一个阻塞队列用来存放线程池中的任务。这里的阻塞队列可以根据需要进行选择如果是需要优先级就选择PriorityBlockingQueue如果不需优先级且是顺序执行就可用ArrayBlockingQueue还有就是如果得跳跃执行就是用LinkedBlockingQueue threadFactory这是一个线程工厂它是什么时候被用呢就是当Executors在创建线程时要用到这个工厂如下是它的源码 最后一个参数是RejectedExecutionHandler叫做线程池的拒绝策略线程池能够容纳的线程数是有限的当达到上限时就要进行拒绝 线程池的拒绝策略 有以上四种 AbortPolicy直接抛异常 CallerRunsPolicy新加的任务让添加任务的线程执行 DiscardOidestPolicy抛弃线程池中最早添加到任务然后执行新任务 DiscardPolicy直接抛弃新任务不执行 线程池中设置存放多少个线程更加合适 假设有N个cpu逻辑核心放N个N1个2N个无法确定 当所有代码为cpu密集型时就是需要进行各种算术运算逻辑判断线程数不应超过N超过了也无法提高效率 当所有代码为IO密集型时就是总是进行读硬盘IO操作就用大于N因为这些操作不吃cpu一个核心可通过调度来并发执行。 所以正确的做法是进行试验对程序进行性能测试验证需要多少个线程数 2.自己实现线程池 首先要有一个阻塞队列用来存放提交的任务然后就是任务的提交操作 假设我们是在创建一个有固定线程数目的线程池那么这个指定数目应该在构造方法中体现同时还得有一个类专门描述这些线程要干的任务就是不停的从队列中拿取任务并进行运行。先来看看如何用一个类来描述每一个线程的任务 本来我是想着给run一个参数到时候调用run时将线程池中存放任务的队列传给工作线程然后让工作线程从里面取任务。但突然想到这个run方法是重写自Thread的不能随便修改参数所以我们要另辟蹊径办法如下 我们可以像上面一样在调用worker构造方法时将线程池里面的阻塞队列当作参数传给worker即可。 那么最后就是线程池的构造方法啦 创建出n个工作线程并让它们开始工作 这里可以优化一下就是用一个数据结构将这些工作线程也组织起来如下 那么线程池如何使用呢如下 哎发现打印操作报错啦为什么这就是变量捕获所以不能直接使用i而应如下操作 最终自定义线程池的代码就如下 class MyThreadPool{//用阻塞队列将添加的任务组织起来private BlockingQueueRunnable queuenew LinkedBlockingQueue();//添加任务public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}//将工作线程组织起来private ListWorkerThread workersnew LinkedList();//创建出指定数目的工作线程public MyThreadPool(int n){for(int i0;in;i){WorkerThread workerThreadnew WorkerThread(this.queue);workerThread.start();workers.add(workerThread);}}//一个类用来描述每个工作线程要做什么static class WorkerThread extends Thread{private BlockingQueueRunnable queuenull;public WorkerThread(BlockingQueueRunnable queue){this.queuequeue;}//反复从队列中拿取元素当队列为空时就阻塞等待Overridepublic void run() {while(true){try {Runnable runnablequeue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}}} } public class Test1 {public static void main(String[] args) throws InterruptedException {MyThreadPool poolnew MyThreadPool(10);for(int i0;i1000;i){int idi;pool.submit(()-{System.out.println(执行任务id);});}} }
http://www.zqtcl.cn/news/212435/

相关文章:

  • 建设网站的要求吗网站怎么建立
  • 网站结构有哪些建设局平台
  • 高端网站建设公司服务好吗有哪些制作网站的公司
  • 网站整站模板下载工具淮安网站建设案例
  • 网站前台用什么做广东省网站设计师
  • 汕头网站建设公司哪个好百度公司注册地址
  • 创建网站需要什么平台wordpress 卡盟模板
  • 网站开发常用的流程肃宁网站建设公司
  • 站内关键词自然排名优化绍兴网络公司
  • 益阳网站seo免费建造公司网站
  • 网站推广报价教你免费申请个人平台
  • 企网站建设wordpress文章批量上传
  • 福州seo建站网站的icp备案信息是什么
  • 腾讯分分彩做号网站广州顶正餐饮培训学校
  • 低价网站建设制作设计公司网站怎样做地理位置定位
  • 贵州网站seo织梦网站后台默认登陆路径
  • 杭州网站设计哪家公司好百度搜索网站显示图片
  • 新乡专业做淘宝网站房地产平面设计网站
  • 三亚谁做网站做网站导航的
  • 厦门酒店网站建设建设网站文案
  • 17网站一起做网店质量怎么样合肥网站建设维护
  • 建站公司外包怎么搭建手机网站m
  • 用ps做网站设计济南品牌网站制作便宜
  • 个人可做网站需要什么材料可以做3d电影网站
  • 温州网站建设专家网站推广软件推广
  • 24淘宝网站建设编程做网站
  • 公司网站模板怎么做自适应网站设计尺寸
  • 滨州正规网站建设价格简单网站制作
  • 创建网站平台电商系统源码
  • 滕州本地网站建设网站维护中模版