java并发编程(一)类、接口和方法

多核的时代,所以面向多核编程很重要,所以java的并发跟多线程的开发就很重要。


1.线程池

WHY:复用线程,可以降低创建线程的开销,因为在线程执行结束后执行回收操作,不是真正去销毁线程。

TestThreadPool.java,本地环境测试,线程中执行很简单,创建线程的开销占整个时间的比例较大,100000次运算的时候,ThreadPoolExecutor:Thread执行时间为,88:6480(ms)

Java中还有定时的线程池,ScheduledThreadPoolExecutor。


2.synchronized

WHY:多线程环境中,thread1跟thread2并发执行时,可能会有不一致情况发生,比如把实例的state读到thread1的时候,在计算、返回到实例内存之前,thread2从实例内存读取了state,这样thread2返回的值就会覆盖thread1返回的值。单线程中不存在这种情况。

可以声明在方法或者代码块,实现互斥和可见性。

细节跟远离,http://blog.csdn.net/hsuxu/article/details/9472371

1)静态方法

public class X{

public synchronized static method1(){}

public synchronized static method2(){}

}

class X级别(包含所有X的实例)method1和method2是互斥的。

2)成员变量方法

public class Y{

public synchronized void method1(){}

public synchronized void method2(){}

}

多线程中,对class Y的同一个实例y而言,y.method1和y.method2是互斥的,thread1 call y.method1跟thread2 call y.method2会互斥。

3)代码块

synchronized (this) block1,跟其他synchronized成员方法是互斥的。

synchronized (Z.class) block1,跟类中synchronized静态方法是互斥的。


3.ReentrantLock

从jdk1.5开始引入,java.util.concurrent.lock,需要显式调用unlock方法,特点

1)tryLock方法可以立刻返回是否取得lock结果false/true,

2)构造ReentrantLock对象的时候,参数可以设置是否公平锁,公平锁严格按照请求的顺序来排队获取锁,非公平锁可以抢占。


4.volatile

只能加在变量前,保证变量在线程间的可见性,但不保证互斥,多线程中可能会发生该变量的状态不一致的情况。

在JVM中该变量不会有线程的本地副本,只会放在主存中,而synchronized保证线程的本地副本与主存的同步,在synchronized写完后(本地副本同步给主存),还需要synchronized读(从主存读取并更新本地副本)


5.Atomics

从jdk1.5开始引入,java.util.concurrent.atomic包,Atomic+CLASS,提供原子操作。

synchronized相比,代码变简洁,性能明显提升。内部通过Java Native Interface的方式使用了硬件支持的CompareAndSwap指令。

细节跟原理,http://blog.csdn.net/hsuxu/article/details/9467651


6.wait、notify和notifyAll

都是Java的Object对象的方法,来实现线程间的状态通信。这三个方法的调用都必须在对象的synchronized块中。notifyAll会唤醒所有等待线程,notify只会唤醒一个等待线程。


7.CountDownLatch

java.util.concurrent包中的一个类,

当多个线程都达到了预期状态,其他线程(可以多个)可以等待这个事件来触发自己的后续工作。多个线程countDwon都执行完成时候,会触发其他线程从await方法返回,执行后面的代码。

初始化的count如果是1,效果就跟wait和notifyAll一样了。


8.CyclicBarrier

可以协同多个线程,让多个线程在这个屏障前等待,直到所有线程都到达了这个屏障的时候,再一起继续执行后面的动作。比如,thread1 call barrier.await方法的时候就会进入阻塞等待状态,直到其他thread也都执行到barrier.await方法到的时候,才会从await返回,继续执行后面的代码。


9.Exchanger

两个线程进行数据交换。线程会阻塞再exchanger1.exchange方法上,直到另一个线程也执行到exchanger1.exchange方法时,二者进行交换。


10.Semaphore

主要用来控制并发数。acquire/release来获取/释放信号,可加个数。

用于管理信号量,构造时传入信号量的数值,每次acquire成功,可用信号量减1,如果没有可用信号量,acquire调用就会阻塞,等待有release调用释放信号后,才能得到信号并返回。

如果管理的信号量为1,就跟互斥锁一个效果了。


11.并发容器

线程安全的容器,不仅线程安全,还要考虑并发性,尽量不用锁,而加锁互斥的就时串行了,降低了并发性。

代表的比如CopyOnWrite和Concurrent开头的几个容器。CopyOnWrite在写的时候重建一次容器,适用与读多写少的场景。Concurrent的原理则不完全相同。

i.e. 使用 CAS 的非阻塞算法
public class NonblockingCounter {
    private AtomicInteger value;
    public int getValue() {
        return value.get();
    }
    public int increment() {
        int v;
        do {
            v = value.get();
        while (!value.compareAndSet(v, v + 1));
        return v + 1;
    }
}
现代的处理器提供了特殊的指令,可以自动更新共享数据,而且能够检测到其他线程的干扰,而 compareAndSet() 就用这些代替了锁定。(如果要做的只是递增计数器,那么 AtomicInteger 提供了进行递增的方法,但是这些方法基于 compareAndSet(),例如 NonblockingCounter.increment())。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值