当前位置:首页 » 编程语言 » java并发包

java并发包

发布时间: 2022-09-25 10:47:48

‘壹’ java并发包源码怎么读

1. 各种同步控制工具的使用

1.1 ReentrantLock

ReentrantLock感觉上是synchronized的增强版,synchronized的特点是使用简单,一切交给JVM去处理,但是功能上是比较薄弱的。在JDK1.5之前,ReentrantLock的性能要好于synchronized,由于对JVM进行了优化,现在的JDK版本中,两者性能是不相上下的。如果是简单的实现,不要刻意去使用ReentrantLock。

相比于synchronized,ReentrantLock在功能上更加丰富,它具有可重入、可中断、可限时、公平锁等特点。

首先我们通过一个例子来说明ReentrantLock最初步的用法:

package test;

import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock = new ReentrantLock(); public static int i = 0;

@Override public void run() { for (int j = 0; j < 10000000; j++)
{ lock.lock(); try
{
i++;
} finally
{ lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}

}

有两个线程都对i进行++操作,为了保证线程安全,使用了ReentrantLock,从用法上可以看出,与synchronized相比,ReentrantLock就稍微复杂一点。因为必须在finally中进行解锁操作,如果不在finally解锁,有可能代码出现异常锁没被释放,而synchronized是由JVM来释放锁。

那么ReentrantLock到底有哪些优秀的特点呢?

1.1.1 可重入

单线程可以重复进入,但要重复退出

lock.lock();
lock.lock();try{
i++;

}
finally{
lock.unlock();
lock.unlock();
}

由于ReentrantLock是重入锁,所以可以反复得到相同的一把锁,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放(重入锁)。这模仿了synchronized的语义;如果线程进入由线程已经拥有的监控器保护的 synchronized 块,就允许线程继续进行,当线程退出第二个(或者后续)synchronized块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个synchronized块时,才释放锁。

public class Child extends Father implements Runnable{ final static Child child = new Child();//为了保证锁唯一
public static void main(String[] args) { for (int i = 0; i < 50; i++) { new Thread(child).start();
}
}
public synchronized void doSomething() {
System.out.println("1child.doSomething()");
doAnotherThing(); // 调用自己类中其他的synchronized方法
}
private synchronized void doAnotherThing() { super.doSomething(); // 调用父类的synchronized方法
System.out.println("3child.doAnotherThing()");
}
@Override
public void run() {
child.doSomething();
}
}class Father { public synchronized void doSomething() {
System.out.println("2father.doSomething()");
}
}

我们可以看到一个线程进入不同的synchronized方法,是不会释放之前得到的锁的。所以输出还是顺序输出。所以synchronized也是重入锁

输出:

1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
...

1.1.2.可中断

与synchronized不同的是,ReentrantLock对中断是有响应的。中断相关知识查看[高并发Java 二] 多线程基础

普通的lock.lock()是不能响应中断的,lock.lockInterruptibly()能够响应中断。

我们模拟出一个死锁现场,然后用中断来处理死锁

package test;import java.lang.management.ManagementFactory;import java.lang.management.ThreadInfo;import java.lang.management.ThreadMXBean;import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock1 = new ReentrantLock(); public static ReentrantLock lock2 = new ReentrantLock(); int lock; public Test(int lock)
{ this.lock = lock;
} @Override
public void run()
{ try
{ if (lock == 1)
{
lock1.lockInterruptibly(); try
{
Thread.sleep(500);
} catch (Exception e)
{ // TODO: handle exception
}
lock2.lockInterruptibly();
} else
{
lock2.lockInterruptibly(); try
{
Thread.sleep(500);
} catch (Exception e)
{ // TODO: handle exception
}
lock1.lockInterruptibly();
}
} catch (Exception e)
{ // TODO: handle exception
} finally
{ if (lock1.isHeldByCurrentThread())
{
lock1.unlock();
} if (lock2.isHeldByCurrentThread())
{
lock2.unlock();
}
System.out.println(Thread.currentThread().getId() + ":线程退出");
}
} public static void main(String[] args) throws InterruptedException {
Test t1 = new Test(1);
Test t2 = new Test(2);
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
Thread.sleep(1000); //DeadlockChecker.check();
} static class DeadlockChecker
{ private final static ThreadMXBean mbean = ManagementFactory
.getThreadMXBean(); final static Runnable deadlockChecker = new Runnable()
{ @Override
public void run()
{ // TODO Auto-generated method stub
while (true)
{ long[] deadlockedThreadIds = mbean.findDeadlockedThreads(); if (deadlockedThreadIds != null)
{
ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds); for (Thread t : Thread.getAllStackTraces().keySet())
{ for (int i = 0; i < threadInfos.length; i++)
{ if(t.getId() == threadInfos[i].getThreadId())
{
t.interrupt();
}
}
}
} try
{
Thread.sleep(5000);
} catch (Exception e)
{ // TODO: handle exception
}
}

}
};
public static void check()
{
Thread t = new Thread(deadlockChecker);
t.setDaemon(true);
t.start();
}
}

}

上述代码有可能会发生死锁,线程1得到lock1,线程2得到lock2,然后彼此又想获得对方的锁。

我们用jstack查看运行上述代码后的情况

下面举个例子:

package test;import java.util.concurrent.CyclicBarrier;public class Test implements Runnable{ private String soldier; private final CyclicBarrier cyclic; public Test(String soldier, CyclicBarrier cyclic)
{ this.soldier = soldier; this.cyclic = cyclic;
} @Override
public void run()
{ try
{ //等待所有士兵到齐
cyclic.await();
dowork(); //等待所有士兵完成工作
cyclic.await();
} catch (Exception e)
{ // TODO Auto-generated catch block
e.printStackTrace();
}

} private void dowork()
{ // TODO Auto-generated method stub
try
{
Thread.sleep(3000);
} catch (Exception e)
{ // TODO: handle exception
}
System.out.println(soldier + ": done");
} public static class BarrierRun implements Runnable
{ boolean flag; int n; public BarrierRun(boolean flag, int n)
{ super(); this.flag = flag; this.n = n;
} @Override
public void run()
{ if (flag)
{
System.out.println(n + "个任务完成");
} else
{
System.out.println(n + "个集合完成");
flag = true;
}

}

} public static void main(String[] args)
{ final int n = 10;
Thread[] threads = new Thread[n]; boolean flag = false;
CyclicBarrier barrier = new CyclicBarrier(n, new BarrierRun(flag, n));
System.out.println("集合"); for (int i = 0; i < n; i++)
{
System.out.println(i + "报道");
threads[i] = new Thread(new Test("士兵" + i, barrier));
threads[i].start();
}
}

}

打印结果:

集合

士兵5: done士兵7: done士兵8: done士兵3: done士兵4: done士兵1: done士兵6: done士兵2: done士兵0: done士兵9: done10个任务完成

1.7 LockSupport

提供线程阻塞原语

和suspend类似

LockSupport.park();
LockSupport.unpark(t1);

与suspend相比不容易引起线程冻结

LockSupport的思想呢,和Semaphore有点相似,内部有一个许可,park的时候拿掉这个许可,unpark的时候申请这个许可。所以如果unpark在park之前,是不会发生线程冻结的。

下面的代码是[高并发Java 二] 多线程基础中suspend示例代码,在使用suspend时会发生死锁。

而使用LockSupport则不会发生死锁。

另外

park()能够响应中断,但不抛出异常。中断响应的结果是,park()函数的返回,可以从Thread.interrupted()得到中断标志。

在JDK当中有大量地方使用到了park,当然LockSupport的实现也是使用unsafe.park()来实现的。

public static void park() { unsafe.park(false, 0L);
}

1.8 ReentrantLock 的实现

下面来介绍下ReentrantLock的实现,ReentrantLock的实现主要由3部分组成:

  • CAS状态

  • 等待队列

  • park()

  • ReentrantLock的父类中会有一个state变量来表示同步的状态

  • /**

  • * The synchronization state.

  • */

  • private volatile int state;

  • 通过CAS操作来设置state来获取锁,如果设置成了1,则将锁的持有者给当前线程

  • final void lock() { if (compareAndSetState(0, 1))

  • setExclusiveOwnerThread(Thread.currentThread()); else

  • acquire(1);

  • }

  • 如果拿锁不成功,则会做一个申请

  • public final void acquire(int arg) { if (!tryAcquire(arg) &&

  • acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

  • selfInterrupt();

  • }

  • 首先,再去申请下试试看tryAcquire,因为此时可能另一个线程已经释放了锁。

    如果还是没有申请到锁,就addWaiter,意思是把自己加到等待队列中去

    其间还会有多次尝试去申请锁,如果还是申请不到,就会被挂起

  • private final boolean parkAndCheckInterrupt() {

  • LockSupport.park(this); return Thread.interrupted();

  • }

  • 同理,如果在unlock操作中,就是释放了锁,然后unpark,这里就不具体讲了。

    2. 并发容器及典型源码分析

    2.1ConcurrentHashMap

    我们知道HashMap不是一个线程安全的容器,最简单的方式使HashMap变成线程安全就是使用Collections.synchronizedMap,它是对HashMap的一个包装

  • public static Map m=Collections.synchronizedMap(new HashMap());

  • 同理对于List,Set也提供了相似方法。

    但是这种方式只适合于并发量比较小的情况。

    我们来看下synchronizedMap的实现

    它会将HashMap包装在里面,然后将HashMap的每个操作都加上synchronized。

    由于每个方法都是获取同一把锁(mutex),这就意味着,put和remove等操作是互斥的,大大减少了并发量。

    下面来看下ConcurrentHashMap是如何实现的

    在ConcurrentHashMap内部有一个Segment段,它将大的HashMap切分成若干个段(小的HashMap),然后让数据在每一段上Hash,这样多个线程在不同段上的Hash操作一定是线程安全的,所以只需要同步同一个段上的线程就可以了,这样实现了锁的分离,大大增加了并发量。

    在使用ConcurrentHashMap.size时会比较麻烦,因为它要统计每个段的数据和,在这个时候,要把每一个段都加上锁,然后再做数据统计。这个就是把锁分离后的小小弊端,但是size方法应该是不会被高频率调用的方法。

    在实现上,不使用synchronized和lock.lock而是尽量使用trylock,同时在HashMap的实现上,也做了一点优化。这里就不提了。

    2.2BlockingQueue

    BlockingQueue不是一个高性能的容器。但是它是一个非常好的共享数据的容器。是典型的生产者和消费者的实现。

‘贰’ Java培训都学什么内容

Java培训主要学的内容如下:

1) Java SE核心技术:Java语言核心编程技术。
2) Java EE Web开发技术:Servlet/JSP/JavaBean编程技术、MVC模式。
3) Java EE流行框架技术:Struts2/Hibernate3/Spring2流行框架。
4) Java EE企业开发通用组件:log4j、JFreeChart、分页、目录树等。
5) UML与设计模式:统一建模语言UML、经典设计模式。
6) 富客户端(RIA)开发:AJAX、Flex等。

java是一门面向对象的编程语言,java语言具有功能强大和简单易用两个特征,具有简单性、面向对象、分布式等特点,可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。

想要了解更多有关Java培训的相关信息,推荐咨询千锋教育。北京千锋互联科技有限公司(下面简称“千锋教育”),成立于2011年1月,立足于职业教育培训领域,公司现有教育培训、高校服务、企业服务三大业务板块。教育培训业务分为大学生技能培训和职后技能培训;高校服务业务主要提供校企合作全解决方案与定制服务;企业服务业务主要为企业提供专业化综合服务。

‘叁’ java并发包有哪些类

1、CyclicBarrier

一个同步辅助类,允许一组线程相互等待,直到这组线程都到达某个公共屏障点。该barrier在释放等待线程后可以重用,因此称为循环的barrier。

来个示例:

[java]view plain

  • packagetest;

  • importjava.util.concurrent.CyclicBarrier;

  • importjava.util.concurrent.ExecutorService;

  • importjava.util.concurrent.Executors;

  • publicclassRecipes_CyclicBarrier{

  • =newCyclicBarrier(10);

  • publicstaticvoidmain(String[]args){

  • ExecutorServiceexecutor=Executors.newCachedThreadPool();//FixedThreadPool(10);

  • for(inti=1;i<=10;i++){

  • executor.submit(newThread(newRunner(i+"号选手")));

  • }

  • executor.shutdown();

  • }

  • }

  • classRunnerimplementsRunnable{

  • privateStringname;

  • publicRunner(Stringname){

  • this.name=name;

  • }

  • @Override

  • publicvoidrun(){

  • System.out.println(name+"准备好了。");

  • try{

  • Recipes_CyclicBarrier.barrier.await();//此处就是公共屏障点,所有线程到达之后,会释放所有等待的线程

  • }catch(Exceptione){

  • }

  • System.out.println(name+"起跑!");

  • }

  • }

  • 2、CountDownLatch

    CountDownLatch和CyclicBarrier有点类似,但是还是有些区别的。CountDownLatch也是一个同步辅助类,它允许一个或者多个线程一直等待,直到正在其他线程中执行的操作完成。它是等待正在其他线程中执行的操作,并不是线程之间相互等待。CountDownLatch初始化时需要给定一个计数值,每个线程执行完之后,必须调用countDown()方法使计数值减1,直到计数值为0,此时等待的线程才会释放。

    来个示例:

    [java]view plain

  • packagetest;

  • importjava.util.concurrent.CountDownLatch;

  • importjava.util.concurrent.CyclicBarrier;

  • importjava.util.concurrent.ExecutorService;

  • importjava.util.concurrent.Executors;

  • publicclassCountDownLatchDemo{

  • =newCountDownLatch(10);//初始化计数值

  • publicstaticvoidmain(String[]args){

  • ExecutorServiceexecutor=Executors.newCachedThreadPool();//FixedThreadPool(10);

  • for(inti=1;i<=10;i++){

  • executor.submit(newThread(newRunner1(i+"号选手")));

  • }

  • executor.shutdown();

  • }

  • }

  • {

  • privateStringname;

  • publicRunner1(Stringname){

  • this.name=name;

  • }

  • @Override

  • publicvoidrun(){

  • System.out.println(name+"准备好了。");

  • CountDownLatchDemo.countDownLatch.countDown();//计数值减1

  • try{

  • CountDownLatchDemo.countDownLatch.await();

  • }catch(Exceptione){

  • }

  • System.out.println(name+"起跑!");

  • }

  • }

  • 3、CopyOnWriteArrayList & CopyOnWriteArraySet

    CopyOnWriteArrayList & CopyOnWriteArraySet是并发容器,适合读多写少的场景,如网站的黑白名单设置。缺点是内存占用大,数据一致性的问题,CopyOnWrite容器只能保证数据最终的一致性,不能保证数据实时一致性。鉴于它的这些缺点,可以使用ConcurrentHashMap容器。

    实现原理:新增到容器的数据会放到一个新的容器中,然后将原容器的引用指向新容器,旧容器也会存在,因此会有两个容器占用内存。我们也可以用同样的方式实现自己的CopyOnWriteMap。

    4、ConcurrentHashMap

    ConcurrentHashMap同样是一个并发容器,将同步粒度最小化。

    实现原理:ConcurrentHashMap默认是由16个Segment组成,每个Segment由多个Hashtable组成,数据变更需要经过两次哈希算法,第一次哈希定位到Segment,第二次哈希定位到Segment下的Hashtable,容器只会将单个Segment锁住,然后操作Segment下的Hashtable,多个Segment之间不受影响。如果需要扩容不是对Segment扩容而是对Segment下的Hashtable扩容。虽然经过两次哈希算法会使效率降低,但是比锁住整个容器效率要高得多。

    5、BlockingQueue

    BlockingQueue只是一个接口,它的实现类有ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue、DelayQueue、LinkedBlockingDeque。

    ArrayBlockingQueue:由数据支持的有界阻塞队列。

    LinkedBlockingQueue:基于链接节点、范围任意的阻塞队列。

    PriorityBlockingQueue:无界阻塞队列。

    SynchronousQueue:一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作。

    DelayQueue:Delayed元素的一个无界阻塞队列。

    LinkedBlockingDeque:基于链接节点、范围任意的双端阻塞队列,可以在队列的两端添加、移除元素。

    6、Lock

    Lock分为公平锁和非公平锁,默认是非公平锁。实现类有ReetrantLock、ReetrantReadWriteLock,都依赖于AbstractQueuedSynchronizer抽象类。ReetrantLock将所有Lock接口的操作都委派到Sync类上,Sync有两个子类:NonFairSync和FaiSync,通过其命名就能知道分别处理非公平锁和公平锁的。AbstractQueuedSynchronizer把所有请求构成一个CLH队列,这里是一个虚拟队列,当有线程竞争锁时,该线程会首先尝试是否能获取锁,这种做法对于在队列中等待的线程来说是非公平的,如果有线程正在Running,那么通过循环的CAS操作将此线程增加到队尾,直至添加成功。

    7、Atomic包

    Atomic包下的类实现了原子操作,有对基本类型如int、long、boolean实现原子操作的类:AtomicInteger、AtomicLong、AtomicBoolean,如果需要对一个对象进行原子操作,也有对对象引用进行原子操作的AtomicReference类,还有对对象数组操作的原子类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。原子操作核心思想是CAS操作,然后调用底层操作系统指令来实现。

‘肆’ Java并发包中的几种ExecutorService

FixedThreadPool模式会使用一个优先固定数目的线程来处理若干数目的任务。规定数目的线程处理所有任务,一旦有线程处理完了任务就会被用来处理新的任务(如果有的话)。这种模式与上面的CachedThreadPool是不同的,CachedThreadPool模式下处理一定数量的任务的线程数目是不确定的。而FixedThreadPool模式下最多的线程数目是一定的。 采用FixedThreadPool模式编写客户端程序如下:packagenet.jerryblog.concurrent;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;publicclassFixedThreadPool{publicstaticvoidmain(String[]args){ //三个线程来执行五个任务 ExecutorServiceexec=Executors.newFixedThreadPool(3);for(inti=0;i<5;i++){exec.execute(newLiftOff());}exec.shutdown();}} 3.SingleThreadExecutor模式 SingleThreadExecutor模式只会创建一个线程。它和FixedThreadPool比较类似,不过线程数是一个。如果多个任务被提交给SingleThreadExecutor的话,那么这些任务会被保存在一个队列中,并且会按照任务提交的顺序,一个先执行完成再执行另外一个线程。 SingleThreadExecutor模式可以保证只有一个任务会被执行。这种特点可以被用来处理共享资源的问题而不需要考虑同步的问题。 SingleThreadExecutor模式编写的客户端程序如下:packagenet.jerryblog.concurrent;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;{publicstaticvoidmain(String[]args){ ExecutorServiceexec=Executors.newSingleThreadExecutor();for(inti=0;i<2;i++){exec.execute(newLiftOff());}}}这种模式下执行的结果如下: #0(9)#0(8)#0(7)#0(6)#0(5)#0(4)#0(3)#0(2)#0(1)#0(LiftOff!) 第一个任务执行完了之后才开始执行第二个任务。

‘伍’ ArrayList详解,自动扩容原理




ArrayList<E>:说明ArrayList支持泛型。
extends AbstractList<E> :继承了AbstractList。AbstractList提供List接口的骨干实现,以最大限度地减少“随机访问”数据存储(如ArrayList)实现Llist所需的工作。
implements List<E>:实现了List。实现了所有可选列表操作。
implements RandomAccess:表明ArrayList支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
implements Cloneable:表明其可以调用clone()方法来返回实例的field-for-field拷贝。
implements java.io.Serializable:表明该类具有序列化功能。有序列化功能
下面来看一些比较重要的参数:

ArrayList的实际大小(数组包含真正的元素个数)

执行完构造方法时还是一个空数组,等到add方法执行的时候则会初始化容量为10;

自己穿入想要的容量参数,对容量进行判断如果容量小于零,则会抛出异常,否则会创建一个容量为initialCapacity的空ArrayList

构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。

先来看其中的add()方法:

add方法首先会调用ensureCapacityInternal(size+1)方法,

ensureCapacityInternal(size+1)方法是用来进行容量检查,决定扩容的想要的最小容量,举个例子,第一次扩容的时候,size默认为0则minCapacity(即想要的最小容量)为1,执行完Math.max语句minCapacity就变为10,这个时候也就是进行空构造第一次add的情况,当ensureCapacityInternal(size+1)传入的参数小于默认参数的时候,就把默认参数当做想要的最小容量,如果大于默认参数就把你想要的参数当做想要的最小容量

这个方法是用来判断是否扩容,如果你想要的最小容量大于数组长度则会调用grow方法进行扩容

通过grow方法可以看到新容量为当前数组容量的1.5倍,然后进行判断,如果理论扩容后新的容量小于小于你想要的最小容量(但我觉得这种情况不太可能会出现,因为为了节省空间,假如当前容量为10,只会传入11来和扩容后的进行比较因此我自己认为不会出现if为真的情况)真正的实现扩容其实是Arrays.方法,就是复制数组实现扩容,

但是如果出现了if为真的情况,从这个方法中可以看到数组的理论最大值为Integer的最大值减去8,但是如果你想要的最小容量已经大于数组的理论最大值,则会进行大容量分配为Integer的最大值至此扩容结束,

下面粗略的谈一下快速失败机制(因为对线程还没有一个好的认识)

fail-fast是怎么产生的。步骤如下:

新建了一个ArrayList,名称为arrayList。
向arrayList中添加内容
新建一个“线程a”,并在“线程a”中通过Iterator反复的读取arrayList的值。
新建一个“线程b”,在“线程b”中删除arrayList中的一个“节点A”。
这时,就会产生有趣的事件了。
在某一时刻,“线程a”创建了arrayList的Iterator。此时“节点A”仍然存在于arrayList中,创建arrayList时,expectedModCount = modCount(假设它们此时的值为N)。
在“线程a”在遍历arrayList过程中的某一时刻,“线程b”执行了,并且“线程b”删除了arrayList中的“节点A”。“线程b”执行remove()进行删除操作时,在remove()中执行了“modCount++”,此时modCount变成了N+1!

“线程a”接着遍历,当它执行到next()函数时,调用checkForComodification()比较“expectedModCount”和“modCount”的大小;而“expectedModCount=N”,“modCount=N+1”,这样,便抛出异常,产生fail-fast事件。

至此,我们就完全了解了fail-fast是如何产生的!
即,当多个线程对同一个集合进行操作的时候,某线程访问集合的过程中,该集合的内容被其他线程所改变(即其它线程通过add、remove、clear等方法,改变了modCount的值);这时,就会抛出异常,产生fail-fast事件。

方法1
在单线程的遍历过程中,如果要进行remove操作,可以调用迭代器的remove方法而不是集合类的remove方法。看看ArrayList中迭代器的remove方法的源码:

可以看到,该remove方法并不会修改modCount的值,并且不会对后面的遍历造成影响,因为该方法remove不能指定元素,只能remove当前遍历过的那个元素,所以调用该方法并不会发生fail-fast现象。该方法有局限性。
例子:

方法2
使用java并发包(java.util.concurrent)中的类来代替ArrayList 和hashMap。
比如使用 CopyOnWriterArrayList代替ArrayList,CopyOnWriterArrayList在是使用上跟ArrayList几乎一样,CopyOnWriter是写时复制的容器(COW),在读写时是线程安全的。该容器在对add和remove等操作时,并不是在原数组上进行修改,而是将原数组拷贝一份,在新数组上进行修改,待完成后,才将指向旧数组的引用指向新数组,所以对于CopyOnWriterArrayList在迭代过程并不会发生fail-fast现象。但 CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。
对于HashMap,可以使用ConcurrentHashMap,ConcurrentHashMap采用了锁机制,是线程安全的。在迭代方面,ConcurrentHashMap使用了一种不同的迭代方式。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出,取而代之的是在改变时new新的数据从而不影响原有的数据 ,iterator完成后再将头指针替换为新的数据 ,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变。即迭代不会发生fail-fast,但不保证获取的是最新的数据。

‘陆’ 有哪些Java web里的并发框架,都有哪些

一、并发是一种需求,以下先介绍一下javaweb对于高并发的处理思路:

1、synchronized 关键字

可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。可能锁对象包括: this, 临界资源对象,Class 类对象

2、同步方法

同步方法锁定的是当前对象。当多线程通过同一个对象引用多次调用当前同步方法时, 需同步执行。

3、同步代码块

同步代码块的同步粒度更加细致,是商业开发中推荐的编程方式。可以定位到具体的同步位置,而不是简单的将方法整体实现同步逻辑。在效率上,相对更高。

A)锁定临界对象

同步代码块在执行时,是锁定 object 对象。当多个线程调用同一个方法时,锁定对象不变的情况下,需同步执行。

B)锁定当前对象

4、锁的底层实现

Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现。同步方法 并不是由 monitor enter 和 monitor exit 指令来实现同步的,而是由方法调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的。

5、锁的种类

Java 中锁的种类大致分为偏向锁,自旋锁,轻量级锁,重量级锁。

锁的使用方式为:先提供偏向锁,如果不满足的时候,升级为轻量级锁,再不满足,升级为重量级锁。自旋锁是一个过渡的锁状态,不是一种实际的锁类型。

锁只能升级,不能降级。

6、volatile 关键字

变量的线程可见性。在 CPU 计算过程中,会将计算过程需要的数据加载到 CPU 计算缓存中,当 CPU 计算中断时,有可能刷新缓存,重新读取内存中的数据。在线程运行的过程中,如果某变量被其他线程修改,可能造成数据不一致的情况,从而导致结果错误。而 volatile 修饰的变量是线程可见的,当 JVM 解释 volatile 修饰的变量时,会通知 CPU,在计算过程中, 每次使用变量参与计算时,都会检查内存中的数据是否发生变化,而不是一直使用 CPU 缓存中的数据,可以保证计算结果的正确。

更多、此外还有很多细节需要通过学习去了解和完善,此处就不一一列举了。

二、并发框架

并发框架很多,如ExecutorService、RxJava、Disruptor、Akka等,具体选择哪个(或者都不选择)是根据项目需求选择的,框架本身的差异并不大,基本都是如下模式

‘柒’ 《Java并发编程核心方法与框架高洪岩》pdf下载在线阅读全文,求百度网盘云资源

《Java并发编程核心方法与框架高洪岩》网络网盘pdf最新全集下载:
链接: https://pan..com/s/1IelP2YEUrDDE4wPSvpNH3g

?pwd=xxn5 提取码: xxn5
简介:全书共10章。第1章讲解了线程间的同步性,以及线程间的传输数据控制,即Semaphore和Exchanger类的使用。第2章介绍了在同步处理上更加灵活的工具类CountDownLatch和CyclicBarrier,详细到每个类的API的具体使用与应用场景。第3章是第2章的升级,由于CountDownLatch和CyclicBarrier类都有相应的弊端,所以在JDK 1.7中新增加了Phaser类来解决这些缺点,该类是熟练掌握JDK并发包的必要知识点。第4章是读者应重点掌握的Executor接口与ThreadPoolExecutor线程池,能有效地提高程序运行效率,更好地统筹线程执行的相关任务。第5章讲解Future和Callable的使用,解决线程需要返回值的情况。第6章介绍Java并发包中的CompletionService的使用,因为可以以异步的方式获得任务执行的结果,所以该接口可以增强程序运行效率。第7章介绍接口ExecutorService,该接口提供了若干工具方法来方便执行并发业务。第8章主要介绍ScheledExecutorService的使用,以掌握如何将计划任务与线程池结合使用。第9章主要介绍Fork-Join分治编程,以提升多核CPU的优势,加快程序运行效率。第10章主要介绍并发集合框架,利用好并发框架,事半功倍。

‘捌’ Java培训能学到哪些知识

Java培训能学到哪些知识?目前市面上的Java培训机构非常多,不同的Java培训机构我们学到的知识点可能也会有所区别,学习Java的小伙伴可以在招聘公告上看一下具体的Java工程师的照片需求,关于Java培训其实除了自己努力基本上由Java培训机构控制。

参加Java培训能学到知识吗?Java培训学习能不能学到知识,主要有一下几点决定的:

第一、自己在Java培训班的学习心态有没有放正,学习是否足够的努力,对于不懂的问题是否能够虚心的请教;

第二、目前网上的Java学习资料也是比较多的,在学习之余也可以在网上进行学习,扩展自己是知识;

第三、Java培训班的师资和课程内容如何,老师是否足够强,能够把知识传递给学员,课程是否比较丰富;

学习是一件比较费时间的事情,不管是自学还是Java培训,都是需要学员有足够的信心和努力才能更好是学习。

在昆明北大青鸟参加Java培训会学到哪些知识点呢?下面小编简单概要一下:

第一阶段、Java设计和编程思想

1、Java语言基础

Java语言、Java环境变量、变量、运算符、表达式、分支语句、循环语句、数组、数组应用,行业规范。双色球抽奖程序实现。

2、Java面向对象

类、对象、属性、方法、构造、封装、继承、多态、重写、重载、访问权限控制符、this、super、static、单例设计模式、final、抽象类和接口、模板设计模式、内部类。

3、JavaSE核心类库

Java核心类、Java字符串、日期处理、包装类、集合、数据结构、异常和异常处理、JavaIQ、多线程编程、线程同步机制、并发包、JAVA网络编程、Java泛型、Java反射机制。

4、Java设计

设计原则、设计模式、常见算法、Java新特性、Maven使用SVN版本管理。

第二阶段、数据库技术和Web基础

(H5)

1、Oracle数据库开发

SQL语句、SQL语句原理、SQL语句优化、表、视图、序列、索引、Oracle数据字典、Oracle数据库PL/SQL开发、数据库设计原则。

2、JDBC

JDBC核心API、JDBC优化技术(缓存技术、批处理技术、数据库连接池)。

3、XML

XML语法、XML解析(SAX、DOM、Dom4j)。

4、HTML5(H5)Web前端技术

(H5/CSS3/JS)

基本文档结构、链接、列表、表格、表单;CSS基础语法、盒子模型、浮动布局、定位;JavaScript语言基础、DOM编程、事件模型等。

5、Jquery

HTML5(H5)JQuery、JQuery对象、元素选择、DOM、操作、CSS操作、动画效果、JQuery插件。

6、AJAX框架

Ajax基础、XHR对象、Ajax设计模式、JSON技术、RESTFUL技术。

第三阶段、JAVAWeb技术和主流框架(SSH)

1、JSP&Serviet

JSP语法、JSP标记、自定义标记、JSTL和EL表达式、JSP新特性、MVC设计模式、Service生命周期及Serviet服务器、Serviet过滤器和监听器、Tomcat配置和部署。

2、Spring

SpringIoc、Ioc注入技巧、对象高级配装配(自动装配、模板装配、组件扫描特性、FactoryBean、对象生命周期)、Spring、AOP、原理、Aspectj、SpringJDBC支持

3、MyBatis

MyBatis映射基础,DQL映射,DML映射,结果集映射,高级动态SQL映射,SqlSession的使用,SpringMyBatis整合

4、Redis

Redis原理、Redis命令、JavaRedisAPI、SpringRedis整合、Redis集群和缓存

5、Nginx

Nginx原理、Nginx环境、Nginx、虚拟机、Nginx反向代理、Tomcat服务器集成、NginxURL重写、Session共享技术

Struts2&Hibernate

6、Struts2控制流程、OgnI、Action、Interceptor、Result、FreeMarker、Struts2标记库、Struts2扩展、Strtus2应用、HibemateAPI、Hibemate实体映射技术、Hibemate关系映射技巧、HQL查询、Hibernate缓存技术、SSH整合

第四阶段、大数据技术(Hadoop和Spark)

1、Hadoop

Hadoop基础和环境搭建,HDFS体系结构、MapRece;Hadoop的集群模式、HDFS联盟、利用ZooKeeper来实现Hadoop集群的HA(高可用性)功能,Yarn的任务调度机制,ApacheHive,Pig数据处理,集成Hadoop和Sqoop、Flume以及ApacheKafKa来实现数据的交换,安装部署HBase,Stomm

2、Scala语言

Scala环境搭建、Scala基础语法、模式匹配、重载与构造器、MapRece、元组、继承、StringContext,OptionSomeNone,Tuple;集合方法和运算,future对象同步处理和异步处理返回结果

3、Spark

Spark和Hadoop已成为目前大数据处理领域的核心框架。课程体系详细讲解Spark搭建,Spark-shell的使用,Spark-submit提交应用,Spark的内核设计和实现,并对内核中的实现架构、运行原理进行详细的讲解;Spark生态习题中的各个组件,包括:SparkCore,SharkSQL和SparkStreaming等等。

以上内容是关于参加Java培训可以学习到哪些知识点的内容概要,如果你也想参加Java培训,一定要选择靠谱的Java培训机构,或者来昆明北大青鸟参加Java培训班免费试听课程可能对于学习Java的小伙伴有所帮助。

免责声明:内容来源于公开网络,若涉及侵权联系尽快删除!

热点内容
解压引导 发布:2025-01-02 01:23:25 浏览:654
微信小程序游戏如何设置密码 发布:2025-01-02 01:01:27 浏览:76
php跨域请求 发布:2025-01-02 01:01:24 浏览:785
5复式算法 发布:2025-01-02 01:00:00 浏览:545
androidtts 发布:2025-01-02 00:59:59 浏览:75
监控访问网址 发布:2025-01-02 00:57:15 浏览:333
堡垒机php 发布:2025-01-02 00:56:30 浏览:52
禁止网页脚本 发布:2025-01-02 00:56:30 浏览:809
java培训班入门 发布:2025-01-02 00:56:23 浏览:229
易语言封包拦截源码 发布:2025-01-02 00:50:44 浏览:881