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. Leetcode:637. 二叉树的层平均值

    Leetcode:637. 二叉树的层平均值 Leetcode:637. 二叉树的层平均值 Talk is cheap . Show me the code . /** * Definition fo ...

  2. 为了让她学画画——熬夜用canvas实现了一个画板

    前言 大家好,我是Fly, canvas真是个强大的东西,每天沉迷这个无法自拔, 可以做游戏,可以对图片处理,后面会给大家分享一篇,canvas实现两张图片找不同的功能, 听着是不是挺有意思的, 有点 ...

  3. CentOS7.9安装Oracle 12C数据库实战

    准备工作(先安装好以下软件): 1.服务器操作系统 CentOS7.9 2.Shell工具:Xshell 7免费版 3.Xmanager 7软件 =========================== ...

  4. REM 根据卷标搜索随身固态U盘的盘符.BAT

    REM 根据卷标搜索随身固态U盘的盘符.BAT@echo offfor /f "tokens=2 delims==" %%a in ('wmic logicaldisk where ...

  5. GooseFS助力大数据业务数倍提升计算能力

    前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...

  6. 1.9 货仓选址问题——Python

    题目描述 在一条数轴上有 N 家商店,它们的坐标分别为 A1~AN. 现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品. 为了提高效率,求把货仓建在何处,可以使得货仓到每家商店 ...

  7. 1day漏洞反推技巧实战(1)

    学习笔记里的存货(1) 以前看了一篇推特老外做赏金猎人的文章,感触有点深,作者没有写相关漏洞分析,只是说了自己挖了多少个漏洞,这里简单的分析下: 1day漏洞在很多时候至关重要,不管是在红蓝对抗,还是 ...

  8. 计算机专业学了快一年, 只会一点C语言,你好意思说自己是IT专业的?

    目录 一.C/C++入门阶段 学习视频推荐:C++入门基础[B站 小甲鱼] 二.C/C++开发进阶 学习视频推荐:C++进阶[慕课网 免费课] 三.C++开发高级 视频教程:程序设计[中国大学MOOC ...

  9. 嵌入式Linux可用的防火墙——iptables:实现ip白名单、mac地址白名单

    iptables是linux系统下的一个功能强大的模块,不仅可以用作防火墙,还可以实现NAT等众多路由功能.iptables的容器有很清晰的层次关系: 1. iptables是表的容器,iptable ...

  10. CVPR2021 | 重新思考BatchNorm中的Batch

    ​ 前言 公众号在前面发过三篇分别对BatchNorm解读.分析和总结的文章(文章链接在文末),阅读过这三篇文章的读者对BatchNorm和归一化方法应该已经有了较深的认识和理解.在本文将介绍一篇关于 ...