java多线程使用场景_java多线程 —— 两种实际应用场景模拟

转自:https://www.cnblogs.com/juepei/p/3926673.html

最近做的偏向并发了,因为以后消息会众多,所以,jms等多个线程操作数据的时候,对共享变量,这些要很注意,以防止发生线程不安全的情况。

(一)

先说说第一个,模拟对信息的发送和接收。场景是这样的:

就像笔者之前做的消息的发送,一个是服务器,一个是客户端。发送的话,要保证信息100%的发送给客户端,那么发给客户端之后,客户端返回一个消息告诉服务器,已经收到。当服务器一直没有收到客户端返回的消息,那么服务器会一直发送这个信息,直到客户端发送回确认信息,这时候再删除重复发送的这个信息。

为了模拟这个场景,这里写两个线程,一个是发送,一个是接收,把发送的信息,要保存到线程安全的对象里面,防止发生线程安全问题,这里采用concurrenthashmap。

发送代码:

48304ba5e6f9fe08f3fa1abda7d326ab.png

packagecom.TestThread;

/**

* @author 薛定饿的猫

*

* */

importjava.util.Map.Entry;

importjava.util.concurrent.ConcurrentHashMap;

public class PushThread extendsThread {

@Override

public voidrun() {

//TODO Auto-generated method stub

try{

sleep(6000);

while(MainThread.pushmessage.size()>0){

//重发消息

for(EntryhashMap:MainThread.pushmessage.entrySet()){

System.out.println("消息id:"+hashMap.getKey()+"未发送成功,在此重发:"+hashMap.getValue());

}

sleep(1000);

}

} catch(InterruptedException e) {

//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

发送代码,是不断遍历内存对象councurrenthashmap,从中取出信息,不断的重发。其中MainThread.pushmessage是内存对象,在最后一段代码中有定义。

当确认接收到信息后,另外一个线程来删除内存对象。

删除的代码:

48304ba5e6f9fe08f3fa1abda7d326ab.png

packagecom.TestThread;

/**

* @author 薛定饿的猫

*

* */

importjava.util.Map.Entry;

public class RemoveThread extendsThread {

@Override

public voidrun() {

//TODO Auto-generated method stub

try{

for (int i = 0; i < 10000; i++) {

sleep(2000);

for(Entrymap:MainThread.pushmessage.entrySet()){

if (map.getKey()==i) {

System.out.println("成功收到id为:"+map.getKey()+"返回的信息,删除该元素");

MainThread.pushmessage.remove(map.getKey());

}

}

System.out.println("内存对象中的元素数量为:"+MainThread.pushmessage.size());

}

} catch(InterruptedException e) {

//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

这里是来删除已收到的信息,然后从内存中删除,不再发送。

然后写一个主类入口:

48304ba5e6f9fe08f3fa1abda7d326ab.png

packagecom.TestThread;

/**

* @author 薛定饿的猫

*

* */

importjava.util.concurrent.ConcurrentHashMap;

public classMainThread {

public static ConcurrentHashMap pushmessage=new ConcurrentHashMap();

public static voidmain(String[] args) {

for (int i = 0; i < 10; i++) {

pushmessage.put(i, "该消息是id为"+i+"的消息");

}

Thread pushThread=newPushThread();

Thread remove=newRemoveThread();

pushThread.start();

remove.start();

for (int i = 10; i < 20; i++) {

pushmessage.put(i, "又一波到来,消息是id为"+i+"的消息");

}

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

这样两个线程可以轮流的进行各自的事情,并且不会造成数据安全的问题。用这种方式,再结合Androidpn的推送机制,会更加符合实际生产中的应用。

(二)多线程同步计数器

多线程同步计数器,按道理也是可以按照上面的方式来进行处理,定义一个像concurrenthashmap的变量。在java中,确实也有另外一种变量,原子变量Atomic,有AtomicLong,AtomicInteger,AtomicReference这些。

如果在多线程环境下要给一些值赋唯一id的话,这个时候,就要考虑这个id的安全性问题,也就是一致性的问题,不能重复。这里有两个实现的代码:

48304ba5e6f9fe08f3fa1abda7d326ab.png

packagecom.test;

public classThreadCount {

public static voidmain(String[] args) {

Thread[] threads=new Thread[10000];

for (int i = 0; i < 10000; i++) {

threads[i]=newAThread();

threads[i].start();

}

}

}

class AThread extendsThread{

@Override

public voidrun() {

//TODO Auto-generated method stub

@SuppressWarnings("unused")

Counter counter=newCounter();

System.out.println(Counter.calNum());

}

}

classCounter{

private static longnum;

publicCounter(){

synchronized (Counter.class) {

num++;

}

}

public static synchronized longcalNum(){

returnnum;

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

这里创建了10000个线程,每个线程都来访问这个计数器,在构造方法中来进行值的递增。

在计数器中,有两次用到同步,很多人都说用同步,经常会对性能造成影响。于是,用第二种的原子变量,这个性能应该会更好。

代码:

48304ba5e6f9fe08f3fa1abda7d326ab.png

packagecom.test;

importjava.util.concurrent.atomic.AtomicLong;

public classThreadCount {

public static voidmain(String[] args) {

Thread[] threads=new Thread[10000];

for (int i = 0; i < 10000; i++) {

threads[i]=newAThread();

threads[i].start();

}

}

}

class AThread extendsThread{

@Override

public voidrun() {

System.out.println(MyCounter.calNum());

}

}

classCounter{

private static longnum;

publicCounter(){

synchronized (Counter.class) {

num++;

}

}

public static synchronized longcalNum(){

returnnum;

}

}

classMyCounter{

private static AtomicLong num=newAtomicLong();

public static synchronized longcalNum(){

returnnum.incrementAndGet();

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

这样写的话,在调用这个计数器的时候,直接不需要再new一个MyCounter对象。

这样可以作为工具类,直接调用MyCounter的calNum方法。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值