月度归档:2012年03月

深入浅出单实例Singleton设计模式

长时间没有用java单实例模式,现在想起来有点忘了,发些东西大家一起熟悉下。
单实例Singleton设计模式可能是被讨论和使用的最广泛的一个设计模式了,这可能也是面试中问得最多的一个设计模式了。这个设计模式主要目的是想在整个系统中只能出现一个类的实例。这样做当然是有必然的,比如你的软件的全局配置信息,或者是一个Factory,或是一个主控类,等等。你希望这个类在整个系统中只能出现一个实例。当然,作为一个技术负责人的你,你当然有权利通过使用非技术的手段来达到你的目的。比如:你在团队内部明文规定,“XX类只能有一个全局实例,如果某人使用两次以上,那么该人将被处于2000元的罚款!”(呵呵),你当然有权这么做。但是如果你的设计的是东西是一个类库,或是一个需要提供给用户使用的API,恐怕你的这项规定将会失效。因为,你无权要求别人会那么做。所以,这就是为什么,我们希望通过使用技术的手段来达成这样一个目的的原因。
本文会带着你深入整个Singleton的世界,当然,我会放弃使用C++语言而改用Java语言,因为使用Java这个语言可能更容易让我说明一些事情。
Singleton的教学版本
这里,我将直接给出一个Singleton的简单实现,因为我相信你已经有这方面的一些基础了。我们姑且把这具版本叫做1.0版

// version 1.0
public class Singleton
{
    private static final Singleton singleton = null;
    private Singleton()    {    }
    public static Singleton getInstance()
    {
        if (singleton == null)
        {
            singleton = new Singleton();
        }
        return singleton;
    }
}

在上面的实例中,我想说明下面几个Singleton的特点:(下面这些东西可能是尽人皆知的,没有什么新鲜的)
1. 私有(private)的构造函数,表明这个类是不可能形成实例了。这主要是怕这个类会有多个实例。
2. 即然这个类是不可能形成实例,那么,我们需要一个静态的方式让其形成实例:getInstance()。注意这个方法是在new自己,因为其可以访问私有的构造函数,所以他是可以保证实例被创建出来的。
3. 在getInstance()中,先做判断是否已形成实例,如果已形成则直接返回,否则创建实例。
4. 所形成的实例保存在自己类中的私有成员中。
5. 我们取实例时,只需要使用Singleton.getInstance()就行了。
当然,如果你觉得知道了上面这些事情后就学成了,那我给你当头棒喝一下了,事情远远没有那么简单。
Singleton的实际版本
上面的这个程序存在比较严重的问题,因为是全局性的实例,所以,在多线程情况下,所有的全局共享的东西都会变得非常的危险,这个也一样,在多线程情况下,如果多个线程同时调用getInstance()的话,那么,可能会有多个进程同时通过 (singleton== null)的条件检查,于是,多个实例就创建出来,并且很可能造成内存泄露问题。嗯,熟悉多线程的你一定会说——“我们需要线程互斥或同步”,没错,我们需要这个事情,于是我们的Singleton升级成1.1版,如下所示:

// version 1.1
public class Singleton
{
    private static final Singleton singleton = null;
    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        if (singleton == null)
        {
            synchronized (Singleton.class)
            {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

嗯,使用了Java的synchronized方法,看起来不错哦。应该没有问题了吧?!错!这还是有问题!为什么呢?前面已经说过,如果有多个线程同时通过(singleton== null)的条件检查(因为他们并行运行),虽然我们的synchronized方法会帮助我们同步所有的线程,让我们并行线程变成串行的一个一个去 new,那不还是一样的吗?同样会出现很多实例。嗯,确实如此!看来,还得把那个判断(singleton== null)条件也同步起来。于是,我们的Singleton再次升级成1.2版本,如下所示:

// version 1.2
public class Singleton
{
    private static final Singleton singleton = null;
    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        synchronized (Singleton.class)
        {
            if (singleton == null)
            {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

不错不错,看似很不错了。在多线程下应该没有什么问题了,不是吗?的确是这样的,1.2版的Singleton在多线程下的确没有问题了,因为我们同步了所有的线程。只不过嘛……,什么?!还不行?!是的,还是有点小问题,我们本来只是想让new这个操作并行就可以了,现在,只要是进入 getInstance()的线程都得同步啊,注意,创建对象的动作只有一次,后面的动作全是读取那个成员变量,这些读取的动作不需要线程同步啊。这样的作法感觉非常极端啊,为了一个初始化的创建动作,居然让我们达上了所有的读操作,严重影响后续的性能啊!
还得改!嗯,看来,在线程同步前还得加一个(singleton== null)的条件判断,如果对象已经创建了,那么就不需要线程的同步了。OK,下面是1.3版的Singleton。

// version 1.3
public class Singleton
{
    private static final Singleton singleton = null;
    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        if (singleton == null)
        {
            synchronized (Singleton.class)
            {
                if (singleton == null)
                {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

感觉代码开始变得有点罗嗦和复杂了,不过,这可能是最不错的一个版本了,这个版本又叫“双重检查”Double-Check。下面是说明:
1. 第一个条件是说,如果实例创建了,那就不需要同步了,直接返回就好了。
2. 不然,我们就开始同步线程。
3. 第二个条件是说,如果被同步的线程中,有一个线程创建了对象,那么别的线程就不用再创建了。
相当不错啊,干得非常漂亮!请大家为我们的1.3版起立鼓掌!

js提交表单

1.document.forms.from.submit();
document.form.sumbit();
document.form.submit.click();
this.form.submit();
以上几种形式的js表单提交在firefox浏览器下是不起作用的
2.必须遵循w3c标准:
1).获得form时应使用getElementById()方法
2).用.submit()方法提交表单
3).button的name/id绝对不能命名为”submit”
4).form中所有的组件(按钮,文本框等)的name/id也不能命名为”submit”

【更新32/64位简体中文iso】Windows8 客户预览版正式公布

Windows8 客户预览版32/64位简体中文镜像,是iso的哦,走起,少年们!
http://iso.esd.microsoft.com/WCPDL/BD1B8A49393E30CC9C4E5C88457D73E964F1F3B18/Windows8-ConsumerPreview-64bit-ChineseSimplified.iso
http://iso.esd.microsoft.com/WCPDL/BD1B8A49393E30CC9C4E5C88457D73E964F1F3B18/Windows8-ConsumerPreview-32bit-ChineseSimplified.iso
更多语言版本请登录微软官方下载页面:http://windows.microsoft.com/zh-cn/windows-8/iso
ISO 映像
ISO 映像必须转换为可存储在 DVD 或 USB 闪存驱动器上的安装媒体。 本页上提供了相关说明。Windows 开发人员中心提供开发人员工具下载.
英语
64 位 (x64) 下载 (3.1 GB) Sha 1 哈希 – 1288519C5035BCAC83CBFA23A33038CCF5522749
32 位 (x86) 下载 (2.3 GB) Sha 1 哈希 – E91ED665B01A46F4344C36D9D88C8BF78E9A1B39
产品密钥: DNJXJ-7XBW8-2378T-X22TX-BKG7J
中文(简体)
64 位 (x64) 下载 (3.1 GB) Sha 1 哈希 – DF69B851F9A81DECBB16648CC452461894416EB0
32 位 (x86) 下载 (2.3 GB) Sha 1 哈希 – E29A2072745A48C14A1C2E5A61F5230841BEDB45
产品密钥: DNJXJ-7XBW8-2378T-X22TX-BKG7J
法语
64 位 (x64) 下载 (3.1 GB) Sha 1 哈希 – A9358E6799ABEEF29EDBA054AD34849C02C7F51F
32 位 (x86) 下载 (2.3 GB) Sha 1 哈希 – 2EF8013B9F50B93AEAC8068F4827E2C1DC0DC0B1
产品密钥: DNJXJ-7XBW8-2378T-X22TX-BKG7J
德语
64 位 (x64) 下载 (3.1 GB) Sha 1 哈希 – DB1003A47C266697B3832BE2A23319988EE34495
32 位 (x86) 下载 (2.3 GB) Sha 1 哈希 – 91075AEA665C5D6F42A24714B3A3390762C94457
产品密钥: DNJXJ-7XBW8-2378T-X22TX-BKG7J
日语
64 位 (x64) 下载 (3.1 GB) Sha 1 哈希 – A8F0DB12CAECEA0BE8B27EA124F2234212D9103A
32 位 (x86) 下载 (2.3 GB) Sha 1 哈希 – C8A322ED86058086207CAAECD46B4DDACF9E247A
产品密钥: DNJXJ-7XBW8-2378T-X22TX-BKG7J

系统要求

Windows 8 Consumer Preview 能够在支持 Windows Vista 和 Windows 7 的硬件上平稳运行:

  • 处理器: 1 GHz 或更快
  • RAM: 1 GB RAM(32 位)或 2 GB RAM(64 位)
  • 硬盘空间: 16 GB(32 位)或 20 GB(64 位)
  • 图形卡: Microsoft DirectX 9 图形设备或更高版本

若要使用某些特定功能,还需要满足以下附加要求:

  • 若要使用触控,你需要支持多点触控的平板电脑或显示器
  • 要访问 Windows 商店以下载和运行程序,你需要有效的 Internet 连接及至少 1024 x 768 的屏幕分辨率
  • 若要拖拽程序,你需要至少 1366 x 768 的屏幕分辨率

如何从 ISO 映像安装 Windows 8 Consumer Preview

在 Windows 7 中将 ISO 文件转换为 DVD 的最简单方法是使用Windows 光盘映像刻录机. 在运行Windows XP 或 Windows Vista 的电脑上,则需要第三方程序才能将 ISO 文件转换为可安装媒体 – DVD 刻录软件通常提供此功能。 一个选择是 USB/DVD 下载工具(由 Microsoft 商店提供)。 还可以下载Windows 8 Consumer Preview 安装程序,该程序包含的工具可用于从 ISO 文件制作 DVD 或 USB 闪存驱动器(需要 Windows Vista 或 Windows 7)。
 
32 bit
http://ak.or.esd.microsoft.com/pr/WCPDL/8A9D4FDFF736C5B1DBF956B89D6C8FDFD925DACD2/Windows8-ConsumerPreview-32bit-English-x1794225.esd
64 bit
http://ak.or.esd.microsoft.com/pr/WCPDL/8A9D4FDFF736C5B1DBF956B89D6C8FDFD925DACD2/Windows8-ConsumerPreview-64bit-English-x1794226.esd
esd 是 web-installer 下載版本

js页面跳转的几种方法

通过js或者html或者php等动态程序都可以方便的实现跳转,这里搜集了几种页面跳转的方式

js方式的页面跳转
1.window.location.href方式
    <script language="javascript" type="text/javascript">
           window.location.href="http://www.dayanmei.com/";
    </script>
2.window.navigate方式跳转
   <script language="javascript">
    window.navigate("top.jsp");
</script>

3.window.loction.replace方式实现页面跳转,注意跟第一种方式的区别
<script language="javascript">
    window.location.replace("http://www.dayanmei.com");
</script>
有3个jsp页面(1.jsp, 2.jsp, 3.jsp),进系统默认的是1.jsp ,当我进入2.jsp的时候, 2.jsp里面用window.location.replace("3.jsp");与用window.location.href ("3.jsp");从用户界面来看是没有什么区别的,但是当3.jsp页面有一个"返回"按钮,调用window.history.go(-1); wondow.history.back();方法的时候,一点这个返回按钮就要返回2.jsp页面的话,区别就出来了,当用 window.location.replace("3.jsp");连到3.jsp页面的话,3.jsp页面中的调用 window.history.go(-1);wondow.history.back();方法是不好用的,会返回到1.jsp 。
4.self.location方式实现页面跳转,和下面的top.location有小小区别
   <script language="JavaScript">
          self.location=’top.htm’;
   </script>
5.top.location
   <script language="javascript">
          top.location=’xx.jsp’;
   </script>

6.不推荐这种方式跳转
    <script language="javascript">
    alert("返回");
    window.history.back(-1);
   </script>

在php程序中,这种方式跳转前面不能有任何输出
<?php
header("url.php");
?>

meta方式实现跳转(content = 3 单位是秒)
<meta http-equiv=refresh content=3;URL="http://www.dayanmei.com">

总结二:

1. Javascript 返回上一页 history.go(-1), 返回两个页面: history.go(-2);
2. history.back().
3. window.history.forward()返回下一页
4. window.history.go(返回第几页,也可以使用访问过的URL)
例:
<a href="javascript:history.go(-1);">向上一页</a>
response.Write("<script language=javascript>")
response.Write("if(!confirm(‘完成任务?’)){history.back();}")
response.Write("</script>")
response.Write("<script language=javascript>history.go(-1);</script>")
<a href="javascript:history.go(-1);">向上一页</a>
页面跳转:onclick="window.location.href=’list.aspx’"
P.S.
小技巧(JS引用JS):
<script type=text/javascript>
<!–
if (typeof SWFObject == "undefined") {
document.write(‘<scr’ + ‘ipt type="text/javascript" src="/scripts/swfobject-1.5.js"></scr’ + ‘ipt>’);}
//–>
</script>
Javascript刷新页面的几种方法:
1    history.go(0)
2    location.reload()
3    location=location
4    location.assign(location)
5    document.execCommand(‘Refresh’)
6    window.navigate(location)
7    location.replace(location)
8    document.URL=location.href
自动刷新页面的方法:
1.页面自动刷新:把如下代码加入<head>区域中
<meta http-equiv="refresh" content="20">
其中20指每隔20秒刷新一次页面.
2.页面自动跳转:把如下代码加入<head>区域中
<meta http-equiv="refresh" content="20;url=http://www.wyxg.com">
其中20指隔20秒后跳转到http://www.wyxg.com页面
3.页面自动刷新js版
<script language="JavaScript">
function myrefresh()
{
       window.location.reload();
}
setTimeout(‘myrefresh()’,1000); //指定1秒刷新一次
</script>
ASP.NET如何输出刷新父窗口脚本语句
1.   this.response.write("<script>opener.location.reload();</script>");
2.   this.response.write("<script>opener.window.location.href = opener.window.location.href;</script>");
3.   Response.Write("<script language=javascript>opener.window.navigate(”你要刷新的页.asp”);</script>")
JS刷新框架的脚本语句
//如何刷新包含该框架的页面用
<script language=JavaScript>
   parent.location.reload();
</script>
//子窗口刷新父窗口
<script language=JavaScript>
    self.opener.location.reload();
</script>
( 或 <a href="javascript:opener.location.reload()">刷新</a>   )
//如何刷新另一个框架的页面用
<script language=JavaScript>
   parent.另一FrameID.location.reload();
</script>
如果想关闭窗口时刷新或者想开窗时刷新的话,在<body>中调用以下语句即可。
<body onload="opener.location.reload()"> 开窗时刷新
<body onUnload="opener.location.reload()"> 关闭时刷新
<script language="javascript">
window.opener.document.location.reload()
</script>