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《多线程多人上线通知案例》的更多相关文章

  1. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  2. 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题

    背景起因: 记起以前的另一次也是关于内存的调优分享下   有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...

  3. Elasticsearch之java的基本操作一

    摘要   接触ElasticSearch已经有一段了.在这期间,遇到很多问题,但在最后自己的不断探索下解决了这些问题.看到网上或多或少的都有一些介绍ElasticSearch相关知识的文档,但个人觉得 ...

  4. 论:开发者信仰之“天下IT是一家“(Java .NET篇)

    比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...

  5. 故障重现, JAVA进程内存不够时突然挂掉模拟

    背景,服务器上的一个JAVA服务进程突然挂掉,查看产生了崩溃日志,如下: # Set larger code cache with -XX:ReservedCodeCacheSize= # This ...

  6. 死磕内存篇 --- JAVA进程和linux内存间的大小关系

    运行个JAVA 用sleep去hold住 package org.hjb.test; public class TestOnly { public static void main(String[] ...

  7. 【小程序分享篇 一 】开发了个JAVA小程序, 用于清除内存卡或者U盘里的垃圾文件非常有用

    有一种场景, 手机内存卡空间被用光了,但又不知道哪个文件占用了太大,一个个文件夹去找又太麻烦,所以我开发了个小程序把手机所有文件(包括路径下所有层次子文件夹下的文件)进行一个排序,这样你就可以找出哪个 ...

  8. Java多线程基础学习(二)

    9. 线程安全/共享变量——同步 当多个线程用到同一个变量时,在修改值时存在同时修改的可能性,而此时该变量只能被赋值一次.这就会导致出现“线程安全”问题,这个被多个线程共用的变量称之为“共享变量”. ...

  9. Java多线程基础学习(一)

    1. 创建线程    1.1 通过构造函数:public Thread(Runnable target, String name){}  或:public Thread(Runnable target ...

  10. c#与java的区别

    经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...

随机推荐

  1. LC-322. 零钱兑换

    322. 零钱兑换 给你一个整数数组 coins ,表示不同面额的硬币:以及一个整数 amount ,表示总金额. 计算并返回可以凑成总金额所需的 最少的硬币个数 .如果没有任何一种硬币组合能组成总金 ...

  2. string子串匹配(用string自带函数,不涉及char数组转换)

    using namespace std; #include <iostream> #include<string> //第1种,用string自带的s.subdtr()截取任意 ...

  3. Python - if 条件控制

    注意 本篇图片素材都来自慕课网,因为素材过于优秀,直接拿过来了,加水印只是为了防止整篇文章被搬 前言 程序并非是一成不变的向下执行,有的时候也要根据条件的不同选择不一样的代码,这个时候便用到了分支结构 ...

  4. intouch 趋势图Y轴自适应功能完善

    在项目中有利用到历史趋势,其y轴往往展示的是该点的最小/最大值范围,对于曲线波动展示不够友好.故而利用自带方法进行完善,以此记录. Histrend1.MinRange=HTGetAutoScaleV ...

  5. vulnhub-XXE靶机

    仅供个人娱乐 靶机信息 靶机下载地址:https://download.vulnhub.com/xxe/XXE.zip 一.主机探测 二.端口服务识别 nmap -sV 192.168.181.149 ...

  6. Super-Mario-Host(超级玛丽)靶机

    仅供个人娱乐 靶机百度云下载  链接:https://pan.baidu.com/s/13l1FUgJjXArfoTOfcmPsbA 提取码:a8ox 一.主机发现 arp-scan -l 二.漏洞扫 ...

  7. anyRTC SDK 5月迭代:优化自定义加密功能,让通信更安全

    anyRTC SDK 5月上新,新增多种加密类型,让实时音视频通信更安全:新增移动端推流支持1080P分辨率的支持:此外还对事件上报.日志详情.数据统计.网络传输等多项功能进行了优化改进. 以下为更新 ...

  8. SQL语句(二)数据排序和单行函数

    目录 一.排序查询 1. 基本排序 2. 多条件排序 二.单行函数 调用方法 字符函数 ①LENGTH函数 ②CONCAT函数 ③upper 和 lower ④substr ⑤instr ⑥trim ...

  9. 离线webpack创建vue 项目

    参考地址: https://blog.csdn.net/feinifi/article/details/104578546 画重点: // 需要带上参数--offline表示离线初始化. --offl ...

  10. hg的常用配置

    hg的配置文件分为全局配置和每个Repo自己的配置,Ubuntu系统下全局配置文件是~/.hgrc,Win7系统下是C:\Users\chad\mercurial.ini,各repo的配置文件是$RE ...