有一个下载方法,如果第一个人在下载,第二个人来了就提示他有人正在下载.
请问这个功能如何实现.我定义了一个全局变量设为false,
如果有人操作了.变为true,
方法里判断此变量为true的话,就提示有人下载
请问这种做法对吗

解决方案 »

  1.   

    如果变为true了,那个家伙不小心终止了,flag永远是true的,没有人能够下载咯!
    建议用一个同步方法+全局静态对象!
      

  2.   

    web应用?监控针对某个IP地址和端口的流量,这应该是一个思路吧,如果5分钟之内没流量,我们就可以认为他断开连接了。
      

  3.   

    能再详细点吗?是要写个什么filter来检测流量?
      

  4.   

    用SESSION监听吧,如果有人下载完了或者中断了,你也就可以立即作出反应了...
      

  5.   

    我最初是设置个static的变量。但是发现如果用户中途退出的话,
    就像xblue3说的一样,flag就永远都是true了。
    可是我又不知道他说的全局静态对象怎么个写法。mengweilil说的流量监测,我就更不太会了。dengfeiling说的用session监听。
    session监听一般不是用来统计在线人数的么,怎么用到我这里呢?
      

  6.   

    那个方法弄成同步的不就可以了?加synchronized关键字修饰
      

  7.   

    全局的flag可以呀,为什么不行,在方法return前设定成初始值就成了吧,
    不管客户端是不是掐掉不下载,servlet方法总要走完吧?
    当然也要catch expection里面也要重置
      

  8.   

    一个全局变量,servlet开始的时候,先检查这个变量,注意检查这个变量本身也要在同步中.
    如果为false,先高成true,可以进行下载.下载完成后高为false.
    如果为true,直接输出提示.这有什么难的?static Boolean flag = false;
    public void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException { synchronized(flag){
    if(!flag){
    flag = true;
    try{
    response.reset();
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition","attachment; filename=你的文件名");
        //输入文件内容
        //关闭输出
    }catch(Exception e){}
    flag = false;
    }
    else{
    response.reset();
    response.setContentType("text/html");
    response.getWriter().println("你来迟了,兄弟,先玩一会再来吧.");
    }
    }
    }
      

  9.   

    20 楼你自己写的代码自己根本就没运行过,你代码 Bug 大了。
      

  10.   

    注意:同时开两个不同的浏览器来测试更严谨,比如 FF + IE。
    <%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"
             buffer="16kb" autoFlush="true" isThreadSafe="true" session="false"
             import="java.util.concurrent.locks.Lock,java.util.concurrent.locks.ReentrantLock"
    %><%!
    private final Lock idleLock = new ReentrantLock();
    %><%
    if (idleLock.tryLock()) {
    try {
    //下面的 for 用以模拟耗时的下载过程
    for (int i = 0; i < 100;) {
    out.println(++i + "% ");
    out.flush();
    Thread.sleep(160L);  //模拟下载过程的耗时
    }
    } finally {
    idleLock.unlock();
    }
    } else {
    %><?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>SynAccessPage</title>
    </head>
    <body>
    <h1>现在不能处理您的下载请求,请稍后再试!</h1>
    </body>
    </html>
    <%
    }
    %>
      

  11.   

    楼上那个锁不正确,因为只锁了当前JSP生成的Servlet实例,而WEB容器中servlet是可以多实例的,所以一定要static
      

  12.   


    我晕,他那个是对锁的开与关进行判断的方法!!!!参考下这个http://blog.chinaunix.net/u/31357/showart_288005.html
      

  13.   

    我更晕,自己看看锁的实现和锁的范围.别拿什么虽人的文档来说事,java并发编程的序就是原文 抄我的文章.
    你自己开两个实例同时运行看看那个锁还有个P用,如果连这点都不明白就不要来讨论了.
      

  14.   

    另外,一个线程获得重入锁后,其它线程进入没有获得锁并不是马上返回,也就是tryLock并不是立即返回的.
    而是要等待原来那人线程的结束,根本不会立即跳到else那里执行提示.所以你的程序根本没有实际意义.
      

  15.   

    最好的方法是自己设置标识位来判断,下载的那个也是自己写也加标识,2边判断,从而决定了,如果是web的要加static
      

  16.   

    什么叫web的要加static,如果只想控制一个实例的范围,不用static,如果想控制所有实例的范围.一定是static.或者用放在缓冲池中String来作为全局
    互斥对象.用显式锁还是用同步语块作用是一样,在java并发包开发过程中我虽然没有参与开发,但我为他们澄清过线程原语.
    假如
    class ServletTest implements Runnable{
    private final Lock lock = new ReentrantLock();
    public void run(){
    if(lock.tryLock()){
    System.out.println("enter.......");
    try{
    Thread.sleep(10000);
    }
    catch(Exception e){}
    finally{
    lock.unlock();
    }

    }else{
    System.out.println("waiting.......");
    }
    }
    }因为lock不是static的,所以它只能防止同一实例的多个线间的互斥:public class MainTest {
    public static void main(String[] args) throws Exception{
    ServletTest st1 = new ServletTest();
    new Thread(st1).start();
    new Thread(st1).start();

    }
    }
    这两个线程访问的是同一 ServletTest st1的方法,所以那个锁起作用了.结果是:
    enter.......
    waiting.......但如果是两个实例,每个实例是不同的锁,所以不会互斥:
    public class MainTest {
    public static void main(String[] args) throws Exception{
    ServletTest st1 = new ServletTest();
    ServletTest st2 = new ServletTest();
    new Thread(st1).start();
    new Thread(st2).start();

    }
    }
    结果是:enter.......
    enter.......只要改成static的就可以保证多个实例间的互斥.
    另外servlet规范没有规定是一个实例还是多个实例服务,事实上大多数容器在空间的时候是一个实例,繁忙的时候就是多个实例,而且再空闲连一个实例
    都销毁了,需要的时候再创建,可以在init和destory中打印消息就以看出在服务启动后,servlet会不断被创建和销毁,并不是一直生成在那儿的.所以必须保证多实例间互斥才能保证同一时刻只有一个用户访问.
      

  17.   

    Servlet规范对实例的数量是有明确规定的。除非Servlet实现了SingleThreadModel接口,否则Servlet容器只能为每个Servlet声明创建唯一的Servlet实例。23楼的思路是对的,但是的确存在axman存在的问题,原因在于使用了isThreadSafe="true",这就意味着由此jsp生成的servlet实现了SingleThreadModel。解决办法是把isThreadSafe="true"去掉,或者像axman说的在声明idlelock的时候使用static关键字。
      

  18.   

    楼上的你看的规范是2.3以前的了,2.4以后实现已经取消了SingleThreadModel,那个标记只是为了向前兼容,并没有真正实的实现.
    而且也没有限制普通的servlet是一个实例还是多个实例来服务.事实上大多数容器中,对普通的servlet来说,如果你用同一个servet
    类做多个url-mapping你就知道它是多个实例了.它不是用一个实例来服务所有的url-mapping,而是每个实例对应一个mapping.
      

  19.   

    axman 教育的对,我确实没仔细的看清楚,以为是你不知道那个方法的用途,抱歉啊servlet也确实是象 axman,ThirstyCrow 说的那样,会有多个实例
      

  20.   

    Java Servlet Specification Version 2.4 第24页最后一段原文:    For a servlet not hosted in a distributed environment (the default), the servlet
    container must use only one instance per servlet declaration. However, for a serv-
    let implementing the SingleThreadModel interface, the servlet container may
    instantiate multiple instances to handle a heavy request load and serialize requests
    to a particular instance.
      

  21.   


    由于一个Servlet声明中只能有一个url-mapping标签,所以你后面说的一部分我是赞同的。
      

  22.   

    呃...初始化一个全局的变量,当有人访问的时候,将这个访问的用户放入这个变量里,如果变量不为空的话,servlet跳转不允许下载。申请一个线程每一段时间从这个全局的变量中取的用户名,再根据用户名取session,如果session为空的话,servlet允许下载...
    偶是菜鸟不知道这样可以不可以.....
      

  23.   

    哈哈,你不要断章取义啊.正好为我提供了一个证据,我起先只想到一个servlet的多个mapping有多个实例,还忘记了分布式的情问下也是多个实例.
    所以说一个servlet在很多情况下会有多个实例.你的那个文档应该是没有及时更新.比如JDBC从1.0到3.0中大对象的例子都是错误的,都是从上一版COPY过来的.2.4的主要更新中明确说明:
    改为Schema后主要加强了两项功能: 
    (1) 元素不依照顺序设定 
    (2) 更强大的验证机制 
    主要体现在: 
    a.检查元素的值是否为合法的值 
    b.检查元素的值是否为合法的文字字符或者数字字符 
    c.检查Servlet,Filter,EJB-ref等等元素的名称是否唯一 
    2.新增Filter四种设定:REQUEST、FORWARD、INCLUDE和ERROR。 
    3.新增Request Listener、Event和Request Attribute Listener、Enent。 
    4.取消SingleThreadModel接口。当Servlet实现SingleThreadModel接口时,它能确保同时间内,
    只能有一个thread执行此Servlet。 
    5.<welcome-file-list>可以为Servlet。 
    6.ServletRequest接口新增一些方法。 
    public String getLocalName() 
    public String getLocalAddr() 
    public int getLocalPort() 
    public int getRemotePort() 取消SingleThreadModel是它专门作为新特性来阐述的.
      

  24.   

    不知道,符不符合你的要求。    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");        if (getFlag()) {
                g_1(request, response);
            } else {
                g_2(request, response);
            }
        }    protected void g_1(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            PrintWriter out = response.getWriter();
            try {
                //
            } finally {
                out.close();
                flag = true;
            }
        }    protected void g_2(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            PrintWriter out = response.getWriter();
            try {
                //
            } finally {
                out.close();
            }
        }    private static synchronized boolean getFlag() {
            if (flag) {
                flag = false;
                return true;
            } else {
                return false;
            }
        }
        private static boolean flag = true;
      

  25.   

    看了看,还挺有意思的,一起说说
    我认为servlet如果没有配多个MAPPING(我没配过),没有负载平衡,分布等
    那么它在一个容器里面默认应该只有一个实例,除非实现SingleThreadModel接口我用JProfile做了下小实验,在本机中访问同一个 servlet 只有一个实例,这个实例其实是多线程的不过我觉得应该按照axman说的 设成  static 比较好
      

  26.   


    23 楼代码实际运行试试(按你说的把 idleLock 声明成静态的),我拿 Tomcat6.0.18 测试没问题。
      

  27.   


    是你弄错了,JSP 中 page 指令 isThreadSafe 属性的默认值就是 true,即加不加 isThreadSafe="true" 都一个样,我这里加上只是为了强调一下此处的默认设置。而 isThreadSafe="false" 才是同一时间只允许一个线程执行此 JSP 页。
      

  28.   

    如 axman 所说,23 楼代码把 idleLock 声明成静态的更好,以免在部属描述文件中多个 Servlet 声明加多个 Servlet 映射产生多个 Servlet 实例响应客户端请求带来的问题,这也是我 23 楼用 JSP 页实现而没有选用 Servlet 实现的原因。因为大多数情况下都不需要对 JSP 页作 Servlet 声明和映射(虽然可以),因而不考虑分布式部属环境再将 idleLock 声明成静态的完全能满足一般的需要。