一段JAVA代码了解多线程,JUC、CAS原子性操作。

  @Test
    public void testPaceController_multiThread() throws InterruptedException {
        final PaceController paceController = new PaceController(1000, 160d);
        final Node node = mock(Node.class);

        final AtomicInteger passcount = new AtomicInteger();
        final AtomicInteger blockcount = new AtomicInteger();

        final AtomicInteger done = new AtomicInteger();
       AtomicLong lastTm = new AtomicLong(System.currentTimeMillis() / 1000);
        int count = 1000;
        final CountDownLatch countDown = new CountDownLatch(count);

        for (int i = 0; i < count; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int j =0; j< 10; j++) {
                        boolean pass = paceController.canPass(node, 1).isPass();

                        if (pass == true) {
                            passcount.incrementAndGet();
                        } else {
                            blockcount.incrementAndGet();
                        }
                        done.incrementAndGet();
                        long now = System.currentTimeMillis() / 1000;
                        if (lastTm.get() != now) {
                            System.out.println("pass:" + passcount.get() + ", tm:" + lastTm.get());
                            System.out.println("block:" + blockcount.get() + ", tm:" + lastTm.get());
                            System.out.println("done:" + done.get() + ", tm:" + lastTm.get());
                            passcount.set(0);
                            blockcount.set(0);
                            done.set(0);
                        }
                        lastTm.set(now);
                    }
                    countDown.countDown();
                }
            }, "Thread " + i);
            thread.start();
        }
        countDown.await();
        System.out.println("pass:" + passcount.get() + ", tm:" + lastTm.get());
        System.out.println("block:" + blockcount.get() + ", tm:" + lastTm.get());
        System.out.println("done:" + done.get() + ", tm:" + lastTm.get());

    }
1.CountDownLatch 同步并发处理
countDown.countDown 递减为0,等待发射信号。

countDown.await()阻塞当前线程,等待调用。
2.AtomicInteger 和 volatile 的区别,CAS原子性操作。

volatile关键字很重要的两个特性:

1、保证变量在线程间可见,对volatile变量所有的写操作都能立即反应到其他线程中,换句话说,volatile变量在各个线程中是一致的(得益于java内存模型—"先行发生原则");

2、禁止指令的重排序优化;

所以volatile 并非原子性操作。

AtomicInteger非阻塞同步(原子性CAS)

同步:多线程并发访问共享数据时,保证共享数据再同一时刻只被一个或一些线程使用。

我们知道,阻塞同步和非阻塞同步都是实现线程安全的两个保障手段,非阻塞同步对于阻塞同步而言主要解决了阻塞同步中线程阻塞和唤醒带来的性能问题,那什么叫做非阻塞同步呢?在并发环境下,某个线程对共享变量先进行操作,如果没有其他线程争用共享数据那操作就成功;如果存在数据的争用冲突,那就才去补偿措施,比如不断的重试机制,直到成功为止,因为这种乐观的并发策略不需要把线程挂起,也就把这种同步操作称为非阻塞同步(操作和冲突检测具备原子性)。在硬件指令集的发展驱动下,使得 "操作和冲突检测" 这种看起来需要多次操作的行为只需要一条处理器指令便可以完成,这些指令中就包括非常著名的CAS指令(Compare-And-Swap比较并交换)。《深入理解Java虚拟机第二版.周志明》第十三章中这样描述关于CAS机制:

图取自《深入理解Java虚拟机第二版.周志明》13.2.2
所以再返回来看AtomicInteger.incrementAndGet()方法,它的时间也比较简单

/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
  return next;
}
}

incrementAndGet()方法在一个无限循环体内,不断尝试将一个比当前值大1的新值赋给自己,如果失败则说明在执行"获取-设置"操作的时已经被其它线程修改过了,于是便再次进入循环下一次操作,直到成功为止。这个便是AtomicInteger原子性的"诀窍"了,继续进源码看它的compareAndSet方法:

/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
  return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

可以看到,compareAndSet()调用的就是Unsafe.compareAndSwapInt()方法,即Unsafe类的CAS操作。

原文地址:https://www.cnblogs.com/jay-wu/p/10330874.html

时间: 2024-10-29 10:10:32

一段JAVA代码了解多线程,JUC、CAS原子性操作。的相关文章

jsp页面:js方法里嵌套java代码(是操作数据库的),如果这个js 方法没被调用,当jsp页面被解析的时候,不管这个js方法有没有被调用这段java代码都会被执行?

jsp页面:js方法里嵌套java代码(是操作数据库的),如果这个js 方法没被调用,当jsp页面被解析的时候,不管这个js方法有没有被调用这段java代码都会被执行? 因为在解析时最新解析的就是JAVA代码,不管写哪里,都会最新被解析

【有趣】这段java代码太古怪

首先呢,来一段java代码来开点胃.等等等等,耍我呢,这是java代码? \u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0063\u006c\u0061\u0073\u0073\u0020\u0058\u004a\u004a\u0020\u007b \u0020\u0020\u0020\u0020\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0073\u0074\u0061\u0074\u0069\u0063\u

如果看一段JAVA代码耗了多少内存

简单的方法,如下: Runtime r = Runtime.getRuntime();  r.gc();  long startMem = r.freememory(); // 开始时的剩余内存  你的代码--long orz = startMem - r.freememory(); // 剩余内存 现在 但这当然不够精确,尤其是"你的代码"足够多的时候. 那要怎么样做才能够精确呢?使用,java.lang.instrument ,当然, 首先,我们得会用这个instrument类,参

对一段Java代码的单元测试

public class Student { private String name; private String sex; private int high; private int age; private String school; public Student(String name, String sex ,int high, int age, String school) { this.name = name; this.sex = sex; this.high = high;

在jsp中默认写上的一段java代码表示basePath 的路径的具体的意思是什么?

<% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> request.getScheme();//可以返回当前页面使用的协议,就是“http” request.ge

四种java代码静态检查工具

[转载]常用 Java 静态代码分析工具的分析与比较 转载自 开源中国社区 http://www.oschina.net/question/129540_23043 1月16日厦门 OSC 源创会火热报名中,奖品多多哦 »   简介: 本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能.特性等方面对它们进行分析和比较,希望能够帮助 Java 软件开发人员了解静态代码

如何在java代码中调用一个web项目jsp或者servlet

有时候需要调用一个web项目的jsp或者servlet,但是执行内部的代码,并不是打开jsp,例如需要在一段java代码中清除一个web项目中的缓存,那么可以把清除缓存的代码放在该web项目的一个servlet中,只需要执行如下代码: URL url = new URL("http://192.168.2.123:8080/sace/ClearCache"); url.openStream(); openStream() 执行一次相当于一次URL请求,其中url.openStream(

如何使用Java代码将GBK编码格式的工程转换为UTF-8编码格式的工程

唉,总算弄好了--项目立项时工程的编码方式为GBK,可是随着研发的不断深入最终还是决定将工程的编码方式改为UTF-8,这样一来所有含有中文的Java文件内都出现了乱码,上百个文件啊,一个一个改那还不得累死,动了动脑子,写了段Java代码,瞬间搞定,代码如下: package com.ghj.packageofclient; import java.io.File; import java.util.Collection; import org.apache.commons.io.FileUtil

tomcat服务器连接MySQL数据库的JNDI数据源配置以及获得连接的Java代码

->首先将mysql的jar包导入到tomcat/lib文件夹下 ->然后在tomcat/conf/context.xml文件中配置以下内容 <Resource name="jdbc/mysql" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000&quo