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. 龙芯 loongnix20 rc2 初体验

    2021-07-24 v0.0.1 版权声明:原创文章,未经博主允许不得转载 3A5000 昨天发布啦,历史上的昨天是中共一大的第一天. 3A5000 的团购还没开始(大概还是3999左右整机的样子) ...

  2. elementUI的el-input和el-select宽度 一致

    在用vue时,用到了element组件的 el-input 和 el-select(多选框)组件,但是宽度显示不一样,查看了多选框的css,发现element-style是写死的 添加style=&q ...

  3. Spring in Action学习笔记(1)

    Spring基础 IoC 控制反转, 也称为DI-依赖注入 一.装配bean 推荐顺序:自动装配 -> JavaConfig装配 -> XML装配 1. 自动装配 @Component 注 ...

  4. 8.3考试总结(NOIP模拟19)[最长不下降子序列·完全背包问题·最近公共祖先]

    一定要保护自己的梦想,即使牺牲一切. 前言 把人给考没了... 看出来 T1 是一个周期性的东西了,先是打了一个暴力,想着打完 T2 T3 暴力就回来打.. 然后,就看着 T2 上头了,后来发现是看错 ...

  5. linux笔记全(无图版)

    1.ls 查看当前目录下的所有内容 黑色的是文件,蓝色的是文件夹,也就是目录 2.rm -f anaconda-ks. cfg 彻底删除文件(如不确定,则需要先保存备份,也就是快照) 3.ifconf ...

  6. C++ 打印乘法口诀

    1 //嵌套循环 乘法口诀 2 #include <iostream> 3 using namespace std; 4 int main() 5 { 6 int i ,j; 7 for ...

  7. Lateral Movement

    简介 这次去宁夏护网,发现我有的朋友连最基本的横向渗透有些都不晓得,他们问我 我也表达不清楚...,就想着写篇文章总结下吧 (慢慢更..) 可以发我邮箱讨论:muxue@protonmail.com ...

  8. noip模拟35[第一次4题·裂了]

    noip模拟35 solutions 这是我第一次这么正式的考四个题,因为这四个题都出自同一个出题人,并不是拼盘拼出来的. 但是考得非常的不好,因为题非常难而且一直想睡觉.. 有好多我根本就不会的算法 ...

  9. 卓越的教练是如何训练高手的?(谈谈memmove)

    编者按:我们知道,优秀的运动员除了自身的天赋和努力之外,出色的教练必不可少.一个成功的企业除了拥有出类拔萃的员工之外,同样需要一位出色的教练,那就是企业的CEO.由此可见,如果我们要想成为一位优秀的程 ...

  10. Create Shortcut to Get Jar File Meta Information

    You have to get meta information of cobertura.jar with command "unzip -q -c cobertura.jar META- ...