JAVA《多线程多人上线通知案例》
代理类的两种写法:
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;
}
}
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();
}
}
本文来自博客园,作者:余生请多指教ANT,转载请注明原文链接:https://www.cnblogs.com/wangbiaohistory/p/14678719.html

浙公网安备 33010602011771号