工作项目问题总结--websocket,string,stringbuilder,stringbuffer

前言:

最近项目中需要用到websocket进行通信,boss想要在接受消息时增加json串的匹配验证,需要判断收到的消息的“{”“}”进行匹配,使用json传递消息,并经过Base64加密处理。
因为是多线程处理的websocket消息,因此存放匹配的字符时,使用的StringBuffer.

实例

项目代码类MessageServer继承WebSocketServer,实现onMessage(WebSocket conn, String message)方法。
声明全局变量

    private AtomicInteger count= new AtomicInteger(0);  //记录字符串中"{""}"个数,左加右减
    StringBuffer msg = new StringBuffer();  //存放匹配的字符
    StringBuffer websocketId=new StringBuffer(); //存放上次消息处理的websocket标识

具体实现

//前一次解析结果部为完整json,且此次消息不为同一websocket通道传来的消息
if (!msg.toString().isEmpty() && !websocketId.toString().equals(conn.toString())) {
    //释放临时存放msg,忽略上次不完整json
    msg.delete(0, msg.length());
    count=new AtomicInteger(0);
}

msg为内存中存放的已解析过的json消息,若msg不为空,表明上次解析的json串不完整,若上次保存websocketId与此次最新websocket标识不一致,则是两个不同websocket通道传来消息,不完整json串忽略。释放msg,清楚计数器count。

解析过程

websocketId.delete(0, websocketId.length());
        websocketId.append(conn.toString());
        for (int i=0; i < tmpMsg.length();i++) {
            c=tmpMsg.charAt(i);
            msg.append(String.valueOf(c));  
            if (c == '{') {
                count.getAndIncrement();
            } else if (c == '}') {
                count.getAndDecrement();
                //如果count=0,表示收到的msg为完整json串,可进行下一步操作。否则,需暂时保存此串,待收到下一个字符串进行拼接
                if (count.get()==0) {
                    //括号配对后再次解析json格式
                    try {
                        //成功解析的,进行下一步操作。
                        //构建WebsocketMessage
                        WebsocketMessage websocketMessage = 
                            new WebsocketMessage(conn.toString(), msg.toString(), conn.getRemoteSocketAddress().getAddress().getHostAddress());

                        msgQueue.put(websocketMessage);             

                    //释放临时存放msg
                    msg.delete(0, msg.length());
                } else if (count.get() < 0) {
                    //收到的json只包含后半部分,以后无法匹配出正确完整json,丢弃
                    Log4jUtil.info("-----------------------"+websocketId.toString()+" onMessage(): received msg error------------------------" + msg.toString());
                    msg.delete(0, msg.length());
                    count=new AtomicInteger(0);
                    return;
                } else {
                    //收到的json为前半部分,等待下次匹配,此处只输出log
                    if (i == tmpMsg.length()-1) {
                        Log4jUtil.info("-----------------------"+websocketId.toString()+" onMessage(): half  msg------------------------" + msg.toString());
                    }
                }
            } else {
                if (i == tmpMsg.length()-1) {
                    //需解析字符串最后一个字符且不为“}”
                    if (count.get() > 0) {
                        //收到的json为前半部分,等待下次匹配,此处只输出log
                        Log4jUtil.info("-----------------------"+websocketId.toString()+" onMessage(): half  msg------------------------" + msg.toString());
                    } else {
                        //收到json串有误,忽略
                        Log4jUtil.info("-----------------------"+websocketId.toString()+" onMessage(): received msg error------------------------" + msg.toString());
                        msg.delete(0, msg.length());
                        count=new AtomicInteger(0);
                    }
                }
            }
        }

线程安全变量

String、StringBuilder、StringBuffer比较

1.执行速度 StringBuilder > StringBuffer > String
原因:

String:字符串常量
StringBuilder:字符串变量
StringBuffer:字符串变量

String是字符串常量解释:
String中使用字符数组保存字符串,如下修饰符final表明不可更改。

private final char value[];

1 String s = "abcd";
2 s = s+1;

上述代码,JVM解析过程:首先创建对象s,赋值abcd。然后再创建新的对象s,执行第二行代码。并没有改变第一个对象。
每当用Strng操作字符串时,实际上是不断创建新的对象,原来的对象变为垃圾被GC回收,效率低。
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。

char[] value;

线程安全

String: 对象不可变,常量,线程安全。
StringBuffer:线程安全,对方法加了同步锁或调用的方法加了同步锁。

1 public synchronized StringBuffer reverse() {
2     super.reverse();
3     return this;
4 }
5 
6 public int indexOf(String str) {
7     return indexOf(str, 0);        //存在 public synchronized int indexOf(String str, int fromIndex) 方法
8 }

StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含“startle”,而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含“starlet”。

StringBuilder:非线程安全。方法未加同步锁。

在多线程环境下,需要使用StringBuffer保证线程安全。单线程环境下,可使用StringBuilder,速度快。

使用的总结: 1.如果要操作少量的数据用 String
2.单线程环境操作大量数据 StringBuilder
3.多线程环境操作大量数据 StringBuffer

AtomicInteger

AutomicInteger,一个提供原子操作的Integer的类。
基本工作原理是使用了同步synchronized的方法实现了对一个long, integer, 对象的增、减、赋值(更新)操作. 比如对于++运算符AtomicInteger可以将它持有的integer 能够atomic 地递增。在需要访问两个或两个以上 atomic变量的程序代码(或者是对单一的atomic变量执行两个或两个以上的操作)通常都需要被synchronize以便两者的操作能够被当作是一个atomic的单元。
在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

// setup to use Unsafe.compareAndSwapInt for updates  
private static final Unsafe unsafe = Unsafe.getUnsafe();  
private static final long valueOffset;  
private volatile int value;  

这里, unsafe是java提供的获得对对象内存地址访问的类,注释已经清楚的写出了,它的作用就是在更新操作时提供“比较并替换”的作用。实际上就是AtomicInteger中的一个工具。

valueOffset是用来记录value本身在内存的便宜地址的,这个记录,也主要是为了在更新操作在内存中找到value的位置,方便比较。使用volatile将使得VM优化失去作用,导致效率较低,所以要在必要的时候使用,因此AtomicInteger类不要随意使用。

注意:value是用来存储整数的时间变量,这里被声明为volatile,就是为了保证在更新操作时,当前线程可以拿到value最新的值(并发环境下,value可能已经被其他线程更新了)

自增

/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
//这里可以拿到value的最新值
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}

public final boolean compareAndSet(int expect, int update) {
//使用unsafe的native方法,实现高效的硬件级别CAS
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值