java

位置:IT落伍者 >> java >> 浏览文章

关于JAVA多线程并发synchronized的测试与合理使用


发布日期:2023年05月01日
 
关于JAVA多线程并发synchronized的测试与合理使用

在项目开发中 或许会碰到JAVA的多线程处理 为保证业务数据的正常 必须加上锁机制 常用的处理方法一般是加上synchronized关键字 目前JDK版本对synchronized已经做了很好的优化 我们不用再考虑其性能 但在实际使用中 往往由于处理不当 导致系统性能的严重下降 那么该如何合理的使用synchronized 必须对其使用方式有个全面了解 在网上搜寻的资料 给出的是四种使用方式 其实可总结为两种 一个是同步代码块 一个是同步方法体 那么该如何使用 请看下面的测试

准备两个方法 对同一个变量做加法 再对每个方法 分别开十个线程执行

[java]

public class ThreadUnit

{

private int i = ;

private Object obj = new Object()

private Object obj = new Object()

public synchronized Integer doAdd(Long start) throws Exception

{

Threadsleep(

++i;

Threadsleep(

return i;

}

public Integer doAdd(Long start) throws Exception

{

Threadsleep(

++i;

Threadsleep(

return i;

}

}

相关代码

[java]

// 十个线程同时执行方法

for (int i = ; i < ; i++)

{

new Thread(new MessageThread( threadUnit))start()

}

// 十个线程同时执行方法

for (int j = ; j < ; j++)

{

new Thread(new MessageThread( threadUnit))start()

}

线程处理

[java]

public void run()

{

try

{

if (operate ==

{

long start = SystemcurrentTimeMillis()

int i = threadUnitdoAdd(start)

long takeTime = SystemcurrentTimeMillis() start;

Systemoutprintln(doAdd() => i= + i + spendTime= + takeTime + ms

spendTime += takeTime;

}

else

{

long start = SystemcurrentTimeMillis()

int i = threadUnitdoAdd(start)

long takeTime = SystemcurrentTimeMillis() start;

Systemoutprintln(doAdd() => i= + i + spendTime= + takeTime + ms

spendTime += takeTime;

}

}

catch (Exception e)

{

eprintStackTrace()

}

}

运行结果

在两个方法体上都加上synchronized

[java]

public synchronized Integer doAdd(Long start) throws Exception

[java]

public synchronized Integer doAdd(Long start) throws Exception

执行结果

[html]

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

花费时间ms

都是有序执行 变量值没有产生错乱 但花费时间ms

在doAdd方法上加上synchronized doAdd不加

[java]

public synchronized Integer doAdd(Long start) throws Exception

执行结果

[java]

doAdd方法加上synchronized:

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

花费时间ms

doAdd方法瞬间执行完成 之后doAdd方法则是串行有序执行 这时doAdd方法获取的变量值已经错乱 doAdd获取的正常 花费时间ms

两个方法在都没使用synchronized前的情况

执行结果

[java]

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

花费时间ms

可以看到 两个方法的变量值获取已经错乱 但花费时间最少ms

使用同步块 在两个方法内采用不同的对象锁

doAdd:

[java]

synchronized (obj

{

Threadsleep(

++i;

Threadsleep(

return i;

}

doAdd:

[java]

synchronized (obj

{

Threadsleep(

++i;

Threadsleep(

return i;

}

执行结果

[html]

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

花费时间ms

两个方法有序交替执行 互不影响 花费时间ms 相对加锁同一对象执行的时间缩短

使用同步块 使用方法参数作为对象锁

[java]

public Integer doAdd(Long start) throws Exception

{

synchronized (start)

{

Threadsleep(

++i;

Threadsleep(

return i;

}

}

执行结果

[java]

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

花费时间ms

执行效果和第三种情况相同 每个参数作为不同的对象 即便加上synchronized也不能起到锁的效果

把调用的类改为静态类 只在一个方法上加锁

加锁doAdd方法

[java]

public static synchronized Integer doAdd(Long start) throws Exception

执行结果

[html]

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

doAdd() => i= spendTime=ms

花费时间ms

和第二种情形类似 没有加锁的doAdd方法瞬间执行完成 doAdd方法则是串行有序执行

总结

synchronized关键在于锁定的对象 如果是同一对象 那么所有执行线程 必须等待对象锁释放后才能执行 如果是不同对象 那么只对各对象所关联的线程生效

synchronized若加在方法体上 默认锁定的是对象本身 对于所有加锁的方法 都是按照串行规则有序执行 对于没有加锁的方法 不受任何影响 静态类同理

合理使用synchronized 既要保证稳定性 又要保证性能 需要在两者间作出权衡 尽量把synchronized范围细度化 合理控制业务处理流程 对象操作原子化 减少锁的使用

不要盲目在方法体上加synchronized关键字 如果每个方法负责处理的是不同业务 那么尽量采用第四种情形 使用不同的对象锁处理 而不是锁定整个对象

               

上一篇:Java多线程的优先级

下一篇:Java多线程同步-BusyFlag或Lock