JAVA《多线程多人上线通知案例》
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 代理类的两种写法: package com.wangbiao.mybetty.demo; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class PlayerProxy implements InvocationHandler { // public Object getPlayer(Object target) { // return Proxy.newProxyInstance( // target.getClass().getClassLoader(), // target.getClass().getInterfaces(), // // 这里其实是要实现jdk代理InvocationHandler的接口,然后改成JKD8的写法了而已 // (proxy, method, args) -> { // System.out.println("[JDK动态代理]开着法拉利到小区接你"); // // 执行目标对象方法 // Object returnValue = method.invoke(target, args); // System.out.println("[JDK动态代理]开着法拉利送你回家"); // return returnValue; // } // ); // } //真实对象 private Object target; /** * 建立代理对象和真实对象的代理关系方法,并返回代理对象 * @param target 真实对象 * @return 代理对象 */ public Object bing(Object target){ this .target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this ); } /** * * @param proxy 代理对象 * * @param method 当前调度方法 * @param args 当前方法参数 * @return 代理结果返回 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( "进入代理逻辑方法" ); System.out.println( "在调度真实对象之前的服务" ); Object obj = method.invoke(target, args); //相当于调用sayHello方法 System.out.println( "在调度真实对象后的方法" ); return obj; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 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); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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(); } } |
本文来自博客园,作者:余生请多指教ANT,转载请注明原文链接:https://www.cnblogs.com/wangbiaohistory/p/14678719.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了