JAVA《多线程多人上线通知案例》
package com.wangbiao.palyermanager; import com.wangbiao.player.Player; /**
* TODO
*
* @author wangbiao
* @Title TODO
* @module TODO
* @description 多人在线管理器
* @date 2021/4/19 13:26
*/
public interface PlayerManager {
/**
* 增加一个玩家对象。
*/
void addPlayer(Player player) throws InterruptedException; /**
* 根据用户名获取玩家对象。
*/
Player getPlayer(String username); /**
* 向系统中的所有玩家广播一条消息。
*/
void broadcast(String message) throws InterruptedException; }
package com.wangbiao.player; /**
* TODO
*
* @author wangbiao
* @Title TODO
* @module TODO
* @description TODO
* @date 2021/4/19 13:26
*/ /*
题目:实现Player和PlayerManager接口的功能。 要求:
1、Player对象以username为索引,且Player对象创建之后,username不会变化。 》容器
2、PlayerManager中的所有功能是线程安全的,可并发执行。 多线程
3、PlayerManager每隔一分钟会将isOffline() == true的Player对象删除。 timetask》可升级为定时器
4、编写针对PlayerManager功能的单元测试,确保PlayerManager的功能正确。 观察者模式/监听
*/ public interface Player {
/**
* 用户名。
*/
String getUsername(); /**
* 向玩家发送消息。
*/
void write(String message); /**
* 玩家是否掉线。
*/
boolean isOffline(); }
package com.wangbiao; import com.wangbiao.palyermanager.PlayerManager;
import com.wangbiao.player.Player; import java.util.Iterator;
import java.util.Map;
import java.util.Observable;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock; /**
* TODO
*
* @author wangbiao
* @Title TODO
* @module TODO
* @description 线程实现
* @date 2021/4/19 14:45
*/
public class SunCallable implements Callable<String> {
private static ReentrantLock reentrantLock=new ReentrantLock();
private static final Object object = new Object();
private static volatile ConcurrentHashMap<String, Player> hashMap; private ThreadPoolExecutor taskExecutor;
private CountDownLatch latch;
private Player player; public SunCallable(ThreadPoolExecutor taskExecutor, CountDownLatch latch, Player player,ConcurrentHashMap<String, Player> hashMap) {
this.latch = latch;
this.taskExecutor = taskExecutor;
this.player = player;
this.hashMap=hashMap;
} public String call() throws Exception { try {
SunCallable.PlayerManagerInstance playerManagerInstance=new PlayerManagerInstance();
Thread.sleep(1000);
playerManagerInstance.addPlayer(this.player);
Thread.sleep(1000);
playerManagerInstance.broadcast("管理器通知:昵称为《" + this.player.getUsername() + "》上线了");
} finally {
latch.countDown();
} return "ok";
} //静态内部类
static class PlayerManagerInstance extends Observable implements PlayerManager {
public synchronized void addPlayer(Player player) throws InterruptedException {
hashMap.put(player.getUsername(), player);
System.out.println("管理器通知:昵称为《" + player.getUsername() + "》上线了");
setChanged();
notifyObservers(player); } public Player getPlayer(String username) {
return hashMap.get(username); } /**
* 向系统中的所有玩家广播一条消息。
*/
public synchronized void broadcast(String message) throws InterruptedException {
for (Iterator<Map.Entry<String, Player>> iterator = hashMap.entrySet().iterator(); iterator.hasNext(); ) { Map.Entry<String, Player> next = iterator.next();
Player player = next.getValue();
// if (getPlayer(player.getUsername()) == player) {
// continue;
// }
Thread.sleep(1000);
player.write(message);
} }
}
}
package com.wangbiao; import com.wangbiao.player.Player;
import com.wangbiao.player.Player1;
import com.wangbiao.player.PlayerProxy;
import jdk.nashorn.internal.parser.JSONParser;
import netscape.javascript.JSObject; import java.util.Timer;
import java.util.concurrent.*; /**
* TODO
*
* @author wangbiao
* @Title TODO
* @module TODO
* @description TODO
* @date 2021/4/19 13:46
*/
public class PayerTest {
private static volatile ConcurrentHashMap<String, Player> hashMap = new ConcurrentHashMap(); public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor taskExecutor = new ThreadPoolExecutor(500,1000,3000, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
CountDownLatch latch = new CountDownLatch(10);
PlayerProxy playerProxy=new PlayerProxy();
for (int i = 1; i <=10 ; i++) {
//动态代理类在多线程高并发场景下,出现只有一个线程实力有效的情况,所以一个玩家还是一个线程任务比较安全
// Player player=playerProxy.getPlayer(new Player1("玩家"+i)); //巨坑卡了我一个下午
Player1 player1 = new Player1("玩家" + i);
taskExecutor.submit(new SunCallable(taskExecutor,latch,player1,hashMap));
}
MyTimeTask myTimeTask = new MyTimeTask(hashMap);
Timer myTimer=new Timer();
myTimer.schedule(myTimeTask,6000,6000);
latch.await(1,TimeUnit.MINUTES);
taskExecutor.shutdown();
}
}
JAVA《多线程多人上线通知案例》的更多相关文章
- Spark案例分析
一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...
- 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题
背景起因: 记起以前的另一次也是关于内存的调优分享下 有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...
- Elasticsearch之java的基本操作一
摘要 接触ElasticSearch已经有一段了.在这期间,遇到很多问题,但在最后自己的不断探索下解决了这些问题.看到网上或多或少的都有一些介绍ElasticSearch相关知识的文档,但个人觉得 ...
- 论:开发者信仰之“天下IT是一家“(Java .NET篇)
比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...
- 故障重现, JAVA进程内存不够时突然挂掉模拟
背景,服务器上的一个JAVA服务进程突然挂掉,查看产生了崩溃日志,如下: # Set larger code cache with -XX:ReservedCodeCacheSize= # This ...
- 死磕内存篇 --- JAVA进程和linux内存间的大小关系
运行个JAVA 用sleep去hold住 package org.hjb.test; public class TestOnly { public static void main(String[] ...
- 【小程序分享篇 一 】开发了个JAVA小程序, 用于清除内存卡或者U盘里的垃圾文件非常有用
有一种场景, 手机内存卡空间被用光了,但又不知道哪个文件占用了太大,一个个文件夹去找又太麻烦,所以我开发了个小程序把手机所有文件(包括路径下所有层次子文件夹下的文件)进行一个排序,这样你就可以找出哪个 ...
- Java多线程基础学习(二)
9. 线程安全/共享变量——同步 当多个线程用到同一个变量时,在修改值时存在同时修改的可能性,而此时该变量只能被赋值一次.这就会导致出现“线程安全”问题,这个被多个线程共用的变量称之为“共享变量”. ...
- Java多线程基础学习(一)
1. 创建线程 1.1 通过构造函数:public Thread(Runnable target, String name){} 或:public Thread(Runnable target ...
- c#与java的区别
经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...
随机推荐
- 技术期刊 · 天光台高未百尺 | Uber 工程师的 JS 算法课;大数据时代的个人隐私;设计师的 Github;告别 PPT 工程师;从零开始实现的像素画
蒲公英 · JELLY技术期刊 Vol.42 这是一个最好的时代,多样化的平台给了所有人成长发展的机会,各种需求和解决需求的人让人大开眼界:但这也并不是完美的时代,"前端还需要懂什么算法?& ...
- 【动态规划】石子合并 luogu-1880
分析 简单的区间DP AC代码 #include <bits/stdc++.h> using namespace std; #define ms(a,b) memset(a,b,sizeo ...
- 最全总结 JavaScript Array 方法详解
JavaScript Array 指南.png Array API 大全 (公众号: 前端自学社区).png 前言 我们在日常开发中,与接口打交道最多了,前端通过访问后端接口,然后将接口数据二次处理渲 ...
- [TensorFlow2.0]-学习率 激活函数 损失函数
本人人工智能初学者,现在在学习TensorFlow2.0,对一些学习内容做一下笔记.笔记中,有些内容理解可能较为肤浅.有偏差等,各位在阅读时如有发现问题,请评论或者邮箱(右侧边栏有邮箱地址)提醒. 若 ...
- ceph介绍和安装
目录 1.Ceph简介 2.Ceph的特点 3.Ceph的缺点 4.架构与组件 4.1.组件介绍 4.2.存储过程 5.部署 5.1 设置主机名.配置时间同步 5.2 配置添加清华源 5.3 初始化c ...
- 基于ScheduledExecutorService的并发定时任务处理能力测试
测试代码 定时器类 package business.util; import java.util.concurrent.Executors; import java.util.concurrent. ...
- Qt Designer中自定义控件的使用(提升法与插件法)
准备乱写一点Qt自定义Widget在Designer中的使用.可是又不想重复提升法(promotion)及插件法基本用法,因为Manual中Using Custom Widgets with Qt D ...
- Python断言及常用断言函数总结
Python断言 Python assert 语句,又称断言语句,可以看做是功能缩小版的 if 语句,它用于判断某个表达式的值,如果值为真,则程序可以继续往下执行:反之,Python 解释器会报 As ...
- Windows10公钥远程连接Linux服务器
目录 前言 一.环境准备 二.使用步骤 1.服务器安装并配置OpenSSH 2. 本地生成密钥 3. 服务器ssh添加密钥 三 总结 前言 使用公钥远程登陆Linux十分方便,无需输入密码,同时采用V ...
- Let's Encrypt泛域名使用和Nginx配置拆分
上一期写了 使用Let's Encrypt实现网站https化 ,随着二级域名的增多,每个二级域名需要一张 SSL 证书,这可太不优雅了,泛域名表示我可以更优雅. 作者:IT王小二 博客:https: ...