java线程处理失败再建一个线程可以吗

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程处理失败再建一个线程可以吗相关的知识,希望对你有一定的参考价值。

参考技术A 把待处理的对象放到一个阻塞队列里。往队列里填东西时 用new Thread() run()queue.put(),
在处理它的线程run中, 还是那个queue, queue.take();
put和take是一对可阻塞线程的方法。 BlockingQueue在初始化时是需要定个大小的,就是说这个队列最多有多少个东西。put在入里填东西时,如果queue满了,它会阻塞,直到有地方可填。所以你不能直接put,要new一个动态的线程出来,。 那处理它的方法中从里面往出take,如果没有东西可take,它也会阻塞,直到有东西它就往下执行。这样你就不用怕while(true)了,因为没东西可执行时,线程会在take处阻塞线程继续执行。

Java CAS简析

什么是CAS

CAS:Compare and Swap,它是一种原子操作,什么是原子操作,可以在多线程编程中实现数据交换而不被打断。是用来更新变量的,当多个线程使用CAS来更新变量时,只有一个线程可以更新变量的值,其他线程都会失败,失败的线程不回被挂起,而是重试直到成功为止。

CAS实现方式,有三个变量,内存值V,处理器缓存(预期值)A,更新值B。比较内存值与预期值,相等则说明没有其他线程操作共享数据,则更新内存值为B;不等说明共享数据V已经被其他线程改动了,放弃更新操作,重新load共享数据,重试之前操作。

CAS的运用

乐观锁:其实现机制是基于CAS的,每次不加锁,假设没有冲突完成操作,如果有冲突,充实知道成功为止。

Java原子类:AtomicInteger等

源码分析

一起看一下AtomicInteger是怎么实现free-lock的。

private static final Unsafe unsafe = Unsafe.getUnsafe();
      private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

 private volatile int value;
 public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

value 是用volatile 修饰的,可以保证get与set的原子性,但无法保证incrementAndGet读写改的复合操作。其实际调用的方法是unsafe的getAndAddInt

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

unsafe 通过JNI调用C++ 的一些方法,首先是根据内存地址获取到value的值,然后调用compareAndSwapInt,true:更新变量成功,false:不成功。compareAndSwapInt经过汇编后最主要的是CMPXCHG指令,该指令是 操作系统级别的原子操作。所以,抛开C++与汇编源码,可以理解为Java运用了os的原子性来实现无锁编程。

那操作系统是如何保证CAS原子性呢?在写操作前会有一个Lock前缀,它会引发两件事情。

  1. 将当前处理器缓存行的数据写回到内存行。
  2. 这个写缓存操作会使其他CPU里的缓存了该内存地址的数据无效。
使用总线锁保证原子性:

处理器提供一个Lock# 信号,当处理器在总线上输出此信号时,其他处理的请求将被阻塞,改处理器就可以独占共享内存。

缺点:对于多核(32,64),其中一个cpu锁住了总线,其他所有核与内存之间的通信都被锁住了,开销太大。

使用缓存锁保证原子性

直接修改内存,缓存一致性机制来保障操作的原子性。

ABA 问题

一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有变化,其实却变化了,解决思路是加上版本号。

参考:

  1. Java 并发编程的艺术
  2. 用AtomicStampedReference解决ABA问题
  3. 非阻塞同步算法与CAS(Compare and Swap)无锁算法

以上是关于java线程处理失败再建一个线程可以吗的主要内容,如果未能解决你的问题,请参考以下文章

java同时跑两个定时任务一个失败另一个会成功吗

java 一个线程处理多个任务

java的服务是每收到一个请求就新开一个线程来处理吗?tomcat呢?

java 线程池 ---- ThreadPoolExecutor 类

java面试啥是多线程

你懂Java多线程吗Java多线程技能