欢迎来到我的个人网站。交流请加我好友: 919201148。欢迎关注公众号或视频号:蜗牛互联网
Solo  当前访客:4 开始使用

白色蜗牛的互联网心得

我要一步一步往上爬,在最高点乘着叶片往前飞

存档: 2016 年 04 月 (24)

05.构建块

2016-04-29 20:06:51 huayonglun
0  评论    216  浏览

5.1 同步容器 同步容器类包括两部分: Vector和Hashtable,早期JDK的一部分 以上两个的同系容器,在JDK1.2中才被加入的同步包装(wrapper)类 这些类由Collections.synchronizedXXX工厂方法创建 这些类通过封装它们的状态,并对每一个公共方法进行同步而实现了线程安全,这样一次只有一个线程能访问容器的状态 5.1.1 同步容器出现的问题 同步容器都是线程安全的,但对于复合操作,可能需要使用额外的客户端加锁(client-side locking)进行保护。这些复合操作包括: 迭代(反复获取元素,直到获得容器中的最后一个元素) 导航(navigation,根据一定的顺序寻找下一个元素) 条件运算,比如"缺少即加入",检查Map中是否存在关键字K,如果没有,就加入mapping(K,V)。 操作Vector的复合操作可能导致混乱的结果 public static Object getLast(Vector list) { int lastIndex = list.size() - 1; return list.ge....

, ,

03.共享对象

2016-04-26 00:29:12 huayonglun
0  评论    221  浏览

  同步有两个重要方面:原子操作或者划定临界区;内存可见性。我们不仅希望能够避免一个线程修改其他线程正在使用的对象的状态,而且希望确保当一个线程修改了对象的状态后,其他线程能够真正的看到改变。但是没用同步,这些可能都不会发生。你可以使用显式的同步,或者利用内置于类库中的同步机制,来保证对象的安全发布。 3.1 可见性   在没有同步的情况下,编译器,处理器,运行时安排操作的执行顺序可能完全出人意料。在没有进行适当同步的多线程程序中,尝试推断那些“必然”发生在内存中的动作时,你总是判断错误。有一个简单的方法来避免这些复杂的问题:只要数据需要被跨线程共享,就进行恰当的同步 3.1.1 过期数据 没有恰当同步的程序,它能够引起意外的后果:过期数据 当读线程检查ready变量时,它可能看到一个过期的值 除非每一次访问变量都是同步的,否则很可能得到变量的过期值 更坏的情况是,过期既不会发生在全部变量上,也不会完全不出现:一个线程可能会得到一个变量最新的值,但是也可能得到另一个变量先前写入的过期值 过期数据的危害 引起安全错误,导致打印错误数据,或者程序无法终止 使对象引用中的数据更加复杂,比....

, ,

02.线程安全

2016-04-24 19:39:07 huayonglun
0  评论    208  浏览

一些概念 定义: 要求无论是多线程中的时序或交替操作,都要保证不破坏哪些不变约束 编写线程安全的代码,本质上就是 管理对状态的访问,而且通常都是共享的、可变的状态 一个对象的状态: 就是它的数据,存储在状态变量中,比如实例域或静态域 共享 一个变量可以被多个线程访问 可变 变量的值在其生命周期内可以改变 无论何时,只要有多于一个线程访问给定的状态变量,而且其中的某个线程会写入该变量,此时必须使用同步来协调线程对该变量的访问 在没有正确同步的情况下,如果多个线程访问了同一个变量,你的程序就存在隐患。有三种方法修复它: 不要跨线程共享变量 使状态变量变为不可变的 在任何访问状态变量的时候使用同步 2.1 什么是线程安全性 一个类是线程安全的,是指在被多个线程访问时,类可以持续进行正确的行为 线程安全的类封装了任何必要的同步,因此客户不需要自己提供 无状态对象永远是线程安全的 多数Servlet都可以实现为无状态的,这一事实极大地降低了确保Servlet线程安全的负担,只有当Servlet要为不同的请求记录一些信息时,才会将线程安全的需求提到日程上....

, ,

01.介绍

2016-04-24 19:37:21 huayonglun
0  评论    214  浏览

并发的历史 顺序编程模型 线程允许程序控制流的多重分支同时存在于一个进程中,共享进程内资源 线程有时候被成为轻量级进程,大多数现代操作系统时序调度的基本单元 线程的优点 降低开发和维护的开销,提高复杂应用的性能 把异步工作流转化为顺序流,使程序模拟人类工作和交互变得更加容易 把复杂、难以理解的代码转化为直接、简洁的代码,易读写及维护 在GUI应用中改进用户接口的响应性 在服务器应用中提高资源的利用率和吞吐量 简化JVM的实现,垃圾收集器通常运行于一个或多个持续工作的线程之间 大部分至关重要的Java应用都依赖于线程,某种程度上是因为它们的组织结构需要这样 线程的风险 安全危险 常见的并发危险 竞争条件(race condition) 活跃度的危险 线程的使用引入了又一形式的活跃度失败(liveness failure) 活跃度意味着好的事情终究会发生 当一个活动进入某种它永远无法再继续执行的状态时,活跃度失败发生 活跃度失败包括: 死锁(deadlock) 饥饿(starvation) 活锁(livelock) 性能危险 性能:希望好的事情尽快发生 性能问....

, ,

06.任务执行

2016-04-30 02:39:53 huayonglun
0  评论    204  浏览

大多数并发应用程序是围绕执行**任务(task)**进行管理的。所谓任务就是抽象、离散的工作单元(unit of work)。把一个应用程序的工作分离到任务中,可以简化程序的管理; 这种分离还在不同事务间划分了自然的分界线,可以方便程序在出现错误时进行恢复; 同时这种分离还可以为并行工作提供一个自然的结构,有利于提高程序的并发性。 6.1 在线程中执行任务 围绕执行任务来管理应用程序时 第一步要指明一个清晰的任务边界(task boundaries) 理想情况下,任务是独立的活动:它的工作并不依赖于其他任务的状态。结果或者边界效应(side effect)。 独立有利于并发性,如果能得到相应的处理器资源,独立的任务还可以并行执行。 为了使调度与负载均衡并具有更好的灵活性,每项任务只占用处理器的一小部分资源。 在正常的负载下,服务器应用程序应该兼具良好的吞吐量和快速的响应性。 应用程序应该在负荷过载时平缓地劣化,而不应该负载一高就简单地以失败告终。为了达到这些目的,你要选择一个清晰的任务边界,并配合一个明确的任务执行策略 大多数服务器应用程序都选择了下面这个自然的任务边界: ....

, ,

part_1

2016-04-29 20:12:48 huayonglun
0  评论    210  浏览

主要概念和规则 可变状态   所有并发问题都归结为如何协调和访问并发状态,可变状态越少,保证线程安全月容易 尽量将域声明为final类型,除非它们的需要是可变的 不可变对象天生是线程安全的。 不可变对象极大地减轻了并发编程的压力。它们简单而且安全,可以在没有锁或者防御性复制的情况下自由地共享。 封装使管理复杂度变得更可行。 你固然可以存储于全局变量的数据来写一个线程安全类。但是你为什么要这样做? 在对象中封装数据,让他们能够更加容易的保持不变; 在对象中封装同步,使它能够更容易地遵守同步策略 用锁来守护每一个可变变量 对同一不变约束中的所有变量都使用相同的锁 在运行复合操作期间持有锁 在非同步的多线程情况下,访问可变变量的程序是存在隐患的。 不要依赖于可以需要同步的小聪明 在设计过程中就考虑线程安全。或者在文档中明确地说明它不是线程安全的。 文档化你的同步策略 欢迎关注微信公众号,技术,思维,心理,带给你认知的全方位成长。 你的关注,就是对我最大的肯定,我会努力产出的,我们一起成长~ 本文由 永伦的小屋 原创。 转载请注明作者及出处,本文作者为 永伦的小屋。

,

04.组合对象

2016-04-27 02:11:13 huayonglun
0  评论    212  浏览

4.1 设计线程安全的类 设计线程类的过程应该包括下面3个基本要素: 确定对象状态是由哪些变量构成的; 确定限制状态变量的不变约束; 制定一个管理并发访问对象状态的策略 对象的状态首先要从它的域说起。 如果对象的域都是基本类型的,那么这些域就组成了对象的完整状态 一个对象有n个基本域,它的状态就是域值组成的n元组(n-tuple) 如果一个对象的域引用了其他对象,那么它的状态也同时包含了被引用对象的域。比如,LinkedList的状态包括了所有存储在链表中的节点对象的状态 同步策略(synchronization policy)定义了对象如何协调对其状态的访问,并且不会违反它的不变约束或后验条件 它规定了如何把不可变性、线程限制和锁结合起来,从而维护线程的安全性,还指明了哪些锁保护哪些变量。 为了保证开发者与维护者可以分析并维护类,应该将类的同步策略写入文档 4.1.1 收集同步需求 不变约束——状态空间(state space) 对象与变量可能处于的状态的范围 状态空间越小,越容易判断它们 尽量使用final类型的域,可以简化我们对对象的可能状态进行分析 不....

, ,

struts2中指定struts2处理的请求后缀

2016-04-05 01:49:58 huayonglun
0  评论    214  浏览

概述 默认情况下我们都是使用.action后缀访问Action。 其实默认后缀是可以通过常量”struts.action.extension“进行修改的。 我们可以配置Struts 2只处理以.do为后缀的请求路径 <struts> <constant name="struts.action.extension" value="do"/> </struts> 如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。如: <constant name="struts.action.extension" value="do,go"/> 一些常用的常量 <!-- 指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出 --> <constant name="struts.i18n.encoding" value="UTF-8"/> <!-- 该属性指定需要Struts 2处理的请求后缀,该属性的默....

, ,

struts2中动态方法调用和使用通配符定义action

2016-04-07 00:31:11 huayonglun
0  评论    212  浏览

动态方法调用 如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法。 public class HelloWorldAction{ private String message; .... public String execute() throws Exception{ this.message = "我的第一个struts2应用"; return "success"; } public String other() throws Exception{ this.message = "第二个方法"; return "success"; } } 假设访问上面action的URL路径为: /struts/test/helloworld.action要访问action的other() 方法,我们可以这样调用: /struts/test/helloworld!other.action 通常不建议使用动态方法调用,我们可以通过常量关闭动态方法调用。 <constant name="struts.enable.DynamicMethodInvocation" v....

, ,

struts2中为应用指定多个struts配置文件

2016-04-07 00:09:50 huayonglun
0  评论    210  浏览

概述 随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿 为了避免struts.xml文件过于庞大、臃肿,提高Struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件 然后再struts.xml文件中包含其他配置文件 操作 通过<include>元素指定多个配置文件 <struts> <include file="department.xml"/> 一个模块使用一个配置文件 <include file="employee.xml"/> </struts> 通过这种方式,可以将struts2的Action按模块添加到多个配置文件中 欢迎关注微信公众号,技术,思维,心理,带给你认知的全方位成长。 你的关注,就是对我最大的肯定,我会努力产出的,我们一起成长~ 本文由 永伦的小屋 原创。 转载请注明作者及出处,本文作者为 永伦的小屋。

,

struts2中为Action属性注入值

2016-04-05 01:28:24 huayonglun
0  评论    211  浏览

概述 struts2为Action中的属性提供了依赖注入功能 在struts2的配置文件中,我们可以很方便地为Action中的属性注入值。注意:属性必须提供get,set方法。 配置 <action name="helloworld" class="com.liuyong666.action.HelloWorldAction"> <param name="savePath">/resource</param> <result name="success">/WEB-INF/page/hello.jsp</result> </action> 对应类中的变化 public class HelloWorldAction{ private String savePath; public String getSavePath() { return savePath; } public void setSavePath(String savePath) { this.savePath = savePath; } ........

, ,

struts2中struts2的处理流程和对Action的管理方式

2016-04-05 03:27:19 huayonglun
0  评论    216  浏览

处理流程图 web.xml配置文件的常用代码 <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> StrutsPrepareAndExecuteFilter Struts2核心控制器,它只负责拦截由/*指定的所有用户的请求 当用户请求到达时,系统会根据web.xml中配置Filter过滤用户的请求 默认情况下,如果用户的访问路径不带有后缀或者是以.action的后缀作为结尾,这时候请求会转发给....

, ,

科学计数法

2016-04-06 00:08:49 huayonglun
0  评论    207  浏览

题目描述 科学计数法是科学家用来表示很大或很小的数字的一种方便的方法 其满足正则表达式[+-][1-9]“.”[0-9]+E[+-][0-9]+ 即数字的整数部分只有1位,小数部分至少有1位,该数字及其指数部分的正负号即使对正数也必定明确给出 现以科学计数法的格式给出实数A,请编写程序按普通数字表示法输出A,并保证所有有效位都被保留 输入描述: 每个输入包含1个测试用例,即一个以科学计数法表示的实数A。 该数字的存储长度不超过9999字节,且其指数的绝对值不超过9999。 输出描述: 对每个测试用例,在一行中按普通数字表示法输出A,并保证所有有效位都被保留,包括末尾的0。 样例 输入样例1: +1.23400E-03 输出样例1: 0.00123400 输入样例2: 1.2E+10 输出样例2: 12000000000 思路 使用字符串来表示数值; 负指数往前移动小数点,补0; 正指数往后移动小数点,需要时补0或去掉小数点; 表示数值时正号不显示,负号显示; 代码 package com.liuyong666.pat; import java.util.Scanne....

,

剑指Offer之二十五--二叉树中和为某一值的所有路径

2016-04-07 21:10:27 huayonglun
0  评论    214  浏览

题目描述 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。 路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。 解析 先序遍历,将遍历过的结点放到A集合中 当遍历到叶子结点并且和恰好是目标值时,将遍历经过的所有结点放到B集合中,B则是满足题意的一条路径 如果遍历到叶子结点和仍然不等于目标值,那么就移除A集合中添加的结点,修改和,切换到右孩子结点重新计算 如果没有遍历到叶子结点就从孩子结点中继续寻找这样的路径 二叉树定义 class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } 代码实现 public ArrayList<ArrayList<Integer>> findPath(TreeNode root,int target) { /* * currentSum 记录当前和 * pathNodes 保存当前路径扫描过的结点 * ....

, , ,

有理数四则运算

2016-04-12 21:41:05 huayonglun
0  评论    213  浏览

题目描述 本题要求编写程序,计算2个有理数的和、差、积、商。 输入描述: 输入在一行中按照“a1/b1 a2/b2”的格式给出两个分数形式的有理数, 其中分子和分母全是整型范围内的整数,负号只可能出现在分子前,分母不为0。 输出描述: 分别在4行中按照“有理数1 运算符 有理数2 = 结果”的格式顺序输出2个有理数的和、差、积、商。 注意输出的每个有理数必须是该有理数的最简形式“k a/b”,其中k是整数部分,a/b是最简分数部分; 若为负数,则须加括号; 若除法分母为0,则输出“Inf”。 题目保证正确的输出中没有超过整型范围的整数。 输入例子: 5/3 0/6 2/3 -4/2 输出例子: 1 2/3 + 0 = 1 2/3 1 2/3 - 0 = 1 2/3 1 2/3 * 0 = 0 1 2/3 / 0 = Inf 2/3 + (-2) = (-1 1/3) 2/3 - (-2) = 2 2/3 2/3 * (-2) = (-1 1/3) 2/3 / (-2) = (-1/3) 思路 分解分数 将分数形式的字符串,分解成整数+最简真分数形式的字符串 整数....

, , ,

剑指Offer之二十六--复杂链表的复制

2016-04-07 22:21:14 huayonglun
0  评论    208  浏览

题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。 复制一个复杂链表 结点定义 class RandomListNode { int label; RandomListNode next = null; RandomListNode random = null; public RandomListNode(int label){ this.label = label; } } 解析 遍历链表,每个结点后边复制相同的结点,设置next指针 复制结点的特殊指针。如果原始链表上的结点N的random指向S,则它对应的复制结点N的random指向S的下一个结点S 抽取复制结点,连起来得到复制链表 代码实现 public RandomListNode clone(RandomListNode pHead){ cloneNodes(pHead); connectRandomNodes(pHead); return reconnectNodes(pHead); } //复制原始链表的任意结点N并创建新结点N,再把N链....

, ,

剑指Offer之二十二--栈的压入、弹出序列

2016-04-01 17:31:18 huayonglun
0  评论    206  浏览

题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。 假设压入栈的所有数字均不相等。 例如序列12345是某栈的压栈序列,序列45321是该压栈序列对应的一个弹出序列,但43512就不可能是该压栈序列的弹出序列。 解析 栈的特点是FIFO 压入序列是确定的,则压入序列之间的元素可能会经历压入后马上被弹出的情况 具体思路为: 根据弹出序列的第一个值,判断在该元素之前被压入栈的所有元素. 栈顶元素与弹出序列第一个值进行比较,等则判断弹出序列的下一个元素,判断依据同步骤1。 如果所有的元素都被压入栈中,但是两者仍然不相等,说明弹出序列不可能是原序列的弹出序列。 这样一直判断直到弹出序列的最后一个元素。 代码实现 public boolean IsPopOrder(int [] pushA,int [] popA) { boolean possible = false; //存放压入栈中的元素 ArrayList<Integer> data = new ArrayList<Integer>(); if(pushA.l....

,

剑指Offer之二十九--数组中出现次数超过一半的数字

2016-04-18 21:20:35 huayonglun
0  评论    217  浏览

题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。 如果不存在则输出0。 解法1 使用map,键存元素,值存出现的次数 发现有某个元素的次数超过数组长度的一半,则返回该元素 代码实现 public int moreThanHalfNum(int [] array) { if(array == null || array.length == 0){ return 0; } int flag = 0; Map<Integer,Integer> map = new HashMap<Integer,Integer>(); int len = array.length; for(int i = 0; i < len; i++){ if(map.containsKey(array[i])){ map.put(array[i], map.get(array[i]) + 1); }else{ map.put(ar....

, ,

剑指Offer之二十八--字符串的排列

2016-04-18 19:13:05 huayonglun
0  评论    212  浏览

题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列。 例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。 输入描述: 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。 思路: 先不考虑是否出现重读字符,要对一个字符进行全排列,可以把第一个字符和后面的字符看成两部分 而第一个字符后面的字符又可以看成第一个字符和后面两部分,是一个递归过程 只要第一个字符的位置没有到达字符串的末尾就分别将第一个字符与后面的字符进行交换 注意: 第一个字符与后面的某个位置的字符发生交换后,需要再次发生交换,不然顺序就会被打乱 举个例子,在字符串abc中,在把第一个字符看成是a,后面的字符b,c,看成是一个整体的时候,abc这个相对的顺序不能改变 所以当a与b发生交换变成bac之后,需要再次交换两个字符,重新回到abc 代码实现 public ArrayList<String> permutation(String str) { ArrayList<S....

, ,

剑指Offer之二十三--从上往下打印二叉树

2016-04-04 23:43:15 huayonglun
0  评论    214  浏览

二叉树结构 class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } 题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 解析 考察层序遍历 每一次打印一个结点的时候,如果该结点有子节点,则把该结点的子节点放到一个队列的末尾。 接下来到队列的头部取出最早进入队列的结点,重复前面的打印操作,直至队列中所有的结点都被打印出来为止。 代码实现 public ArrayList<Integer> printFromTopToBottom(TreeNode root) { ArrayList<Integer> list = new ArrayList<Integer>(); if(root==null){ return list; } Queue<TreeNode> queue = new LinkedList<TreeNode>....

, , ,
TOP