iteye_17041
iteye_17041
2012-10-11 11:27

多线程,保证用户只存在一个线程。困扰很久,实在没有办法

已采纳

servlet,用户请求的地址。当用户请求之后,会调用control.start();进入一个耗时的操作,循环等待。直到超时或者是打断循环退出继续执行。问题出在else语句块,原来意思是如果是刷新,结束该用户的上一个等待线程,该次请求挂起,这样保证了一个用户只存在一个线程。执行顺序应该是先结束上一个线程再new一个新线程。但执行的接是先new一个线程再结束上一个进程。结束线程我也用线程来控制,但还是不行。希望大家能帮我解决一下、谢谢。这个问题困扰很久了。[code="java"]PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
String receiver = String.valueOf(session.getAttribute("User"));

        ChatControl control = null;
        if (ChatListener.threadMap.get(receiver) == null) {
            System.out.println("============================ threadMap.get(receiver) == null");
            control= new ChatControl();
            ChatListener.threadMap.put(receiver , control);//线程对象塞进map
            control.start();//启用线程

// control.join();
ChatListener.threadMap.remove(receiver);
}else {
System.out.println("============================ threadMap.get(receiver) != null");
//如果是刷新,结束上一个长连接,此连接挂起
StopThreadControl stopThread = new StopThreadControl();
stopThread.setPriority(Thread.NORM_PRIORITY+2);
stopThread.setUser(receiver);
stopThread.start();
stopThread.join();//等待停止线程之后再执行new新的线程,但程序没有按照这样执行
/*
control = new ChatControl();
control.update(receiver);//有可能抢cpu资源引起的,无法控制
control = null;
*/
//挂起
ChatControl control2 = new ChatControl();
ChatListener.threadMap.put(receiver, control2);
control2.start();
// control2.join();
ChatListener.threadMap.remove(receiver);
}
ChatHelper.updateChatToReceived(receiver);//更新到已收到[/code]

ChatControl.java 继承 Thread,run是一个耗时的操作。用户请求会进入此等待
[code="java"]public void run()
{ String threadName = Thread.currentThread().getName();
log.info("当前启动线程是:"+threadName);
Date newDate = DateUtil.getNowDateAndTime();
int i = 0;
while(!done){
try {
System.out.println("循环ing。。。。"+i++);
//睡眠1秒继续等待
sleep(1*1000);
//5分钟返回一次,避免资源一直在占用
if(DateUtil.getTwoTimeSub(DateUtil.getNowDateAndTime(), newDate) >= 5){
break ;
}
} catch (Exception e) {
log.error(Constants.getExceptionString("run()", ChatControl.class));
break;//退出
}
}
log.info("当前结束线程:"+threadName);
}[/code]

StopThreadControl 继承Thread, 让上一个线程退出循环,结束进程
[code="java"] String user;
public void run() {
System.out.println("进入StopThreadControl..........................");
ChatControl control= (ChatControl) ChatListener.threadMap.get(user);
ChatListener.threadMap.remove(user);
if (control != null ) {
control.breakThread();
System.out.println("打断循环.........................................");
}
return ;
}[/code]

[code="java"]public class ChatListener {
static public Map threadMap = new HashMap() ;//保存线程

}[/code]

我查了很多关于多线程编程的资料,但还是不会很好运用。还有多线程异步调用。需要使用内部类吗?希望大家能帮我解决一下,指出代码的问题所在,谢谢、

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

8条回答

  • yuwenchun yuwenchun 9年前

    你这需求似乎没有必要重新new线程吧!
    假设线程ChatControl有如下状态:初始态、运行态、结束态。
    当触发刷新的时候,直接将线程ChatControl状态由运行态回退
    为初始态并重新进入运行态不就得了

    点赞 评论 复制链接分享
  • iteye_6401 iteye_6401 9年前

    设计思路有问题。

    首先这里采用多线程的处理方式主要想解决什么问题?

    采用多线程的方式通常是为了提高应用的吞吐率和响应的及时性。建议对耗时任务采用顺序执行的模式,保持了实现的简单性和应用的安全性。如果非要采用多线程的处理方式,建议参考jdk1.5及更高版本的java.util.concurrent包对多线程并发的处理。

    另外,处理用户刷新操作,建议参考下令牌的机制和struts对重复提交的处理。

    点赞 评论 复制链接分享
  • tmj_159 tmj_159 9年前

    设计问题。
    不要在serlet中启动线程,并且这个线程是是servlet的子线程。

    点赞 评论 复制链接分享
  • iteye_5246 iteye_5246 9年前

    结合锁
    synchronized(getLock(user)) {
    //此段代码 串行执行(即同一个用户)
    }
    在数据库方面也需要调整下。
    添加一个字段。标识当前用户是否登录成功。 如果登录成功,那么把这个字段修改为true
    其他用户登录检测这个字段,如果为true,那么ok.重复登录。

    点赞 评论 复制链接分享
  • iteye_3544 iteye_3544 9年前

    wait notify 完美解决这问题

    点赞 评论 复制链接分享
  • cpszgy cpszgy 9年前

    你的StopThreadControl 执行control.breakThread(); 不知道这个代码你的实现是什么。
    如果你的着个只是将done 这个值改了下。那么你的停止线程执行完不带表你的线程真的停止了。有可能你的control 这个线程正在sleep呢。那么得1S后才会停止。
    所以会出现跟你预想的不一样。要确保你可以在breakThread()方法你原有的代码执行完后再sleep个>1s的时间。那么基本可以确保先停旧的再开新的。我觉得最好的方法是:在ChatControl的while循环结束后添加一个启动新的方法。那就确保是停止旧的启动新的。

    点赞 评论 复制链接分享
  • iteye_16124 iteye_16124 9年前

    问题很多,首先,开新线程高消耗,该用线程池,使用Runnable而不是Thread

    control.breakThread(); 这个方法应该是把done设为true吗,如果是,那么多核多线程间的可见性很重要,得把 done 设为 volatile 的,join完之后,stopThread.join();完之后,各线程是抢占的,不一定谁先完成,如果上一个线程的while(!done)一直不执行,则上一个线程一直不结束

    从while(!done)来看,这是典型的打断,可以直接用 interrupt() ,同时在执行线程里可响应打断的时候判断 isInterrput() 并做好结束工作

    点赞 评论 复制链接分享
  • jinnianshilongnian jinnianshilongnian 9年前

    你说的问题出现在第二次请求时:
    StopThreadControl 和 ChatControl 是两个线程 因此是抢占式的:
    应该:
    1、在StopThreadControl先中断第一个ChatControl
    2、再启动新的ChatControl

    其实没必要要StopThreadControl ,直接在主线程中断第一个 然后启动第二个

    再给你一种思路:
    分配给每个用户一把锁,如
    Map lock;

    getLock(user) {
    }

    同一个用户在访问需要非并发执行时:
    synchronized(getLock(user)) {
    //此段代码 串行执行(即同一个用户)
    }

    点赞 评论 复制链接分享

相关推荐