Javaのマルチスレッドは、コンテナの並行クラスの第二の説明を同時一覧をプログラミング

Javaのマルチスレッドは、コンテナの並行クラスの第二の説明を同時一覧をプログラミング

アウトライン

本稿では詳細に同時コンテナリストおよび試験のArrayList、ベクトルに対応するコードを説明し、CopyOnWriteArrayListとにデータを比較するには、リスト100件のスレッド1000を追加しました

この記事では、第六章のチュートリアルのシリーズ「凱歌は、Java並行処理がJUCパッケージを説明共有」です。あなたがシステムを学びたいのであれば、最初から凱歌(kaigejava)の勧告を見て開始します。

Benpianは初めから、我々は、Javaの同時コンテナを説明するために説明する必要があります。一般的な考え方:コンカレント・コンテナーが何であるかを紹介します。次に、リストに関連した、マップ関連およびキュー関連を説明します。このシリーズは、かなりの数の記事があります。あなたはより良いAの学校に従っていました。

テキスト開始

カテゴリーは、コンカレント・コンテナーを説明します

CopyOneWriteArrayList

コピー・ワン・ライト:コピーされ、書き込み時間。

私たちは、元一覧サブクラスvactorで同期スレッドセーフコンテナであることを知っています。このCopyOneWriteArrayListは彼の同時選択肢として理解することができます。

その基礎となるデータ構造は、数値です。ArrayListのと嘘の違い:コレクション、追加または削除操作の元のコピーは、新しいオブジェクトの動作であるだろうと、オブジェクト内の要素を追加または削除するには、リストインチ 操作が完了したら、新しい配列は元の配列に置き換えられます。

addメソッドのCopyOnWriteArrayListとのソースコードを見てみましょう:

0f9hvE1VwKe

編集します

私たちは、ルックはsetArray方法を取ります。

0f9hvEkrUKu

編集します

私はそれを見つけますか?使用される変数には、2つの重要な変更に一過性と揮発性です。

前回の記事では、メモリは揮発性のキーワードの可視性であることを知っています。だから、transientキーワードは、それをしているのですか?私たちは、ウィキペディアの説明を見てみましょう。

0f9hvFJf70S

編集します

キーワード:キーワード修正過渡メンバ変数は、シリアル化プロセスに参加しません。

コメントの後にソースコードを追加します。

0f9hvG21I1Y

編集します

パブリックブールの追加(E電子){

最終ReentrantLockのロック= this.lock。

//ロックを取得します。

lock.lock();

{試します

//元のコレクションを取得します。

オブジェクト[] =要素のgetArray()。

int型のlen = elements.length。

//将原集合copy一份到新的集合中。并设置新的集合的长度为原集合长度+1

Object[] newElements = Arrays.copyOf(elements, len + 1);

//将需要新增的元数添加到新的素组中

newElements[len] = e;

//将新数组替换原来数据。 使用transient和volatitle关键字修饰的

setArray(newElements);

return true;

} finally {

lock.unlock();

}

}

代码很简单,大致流程如下:

先从ReentrantLock中获取到锁(这样在多线程下可以防止其他线程来修改容器list里面内容了);

通过arrays.copyOf方法copy出一份原有数组长度+1;

将要添加的元素赋值给copy出来的数组;

使用setArray方法将新得数组替换原有素组。

因为都是List集合。我们就拿ArrayList、vector以及CopyOnWriteArrayList进行比较:

ArrayList、vector以及CopyOnWriteArrayList比较

业务场景描述:

启动100个线程,向对象中添加1000个数据。查看各自运行结果耗时及插入数据总数。代码在文章最后凯哥会贴出来。

先用线程非安全的arrayList执行效果:

0f9hvGWrN0C

编辑

执行arryList时间为 : 112毫秒!

List.size() : 93266

我们发现list的长度不对。正确的应该是100*1000.从结果来看,arrayList丢数据了。

使用Vector执行后的效果:

0f9hvH2AVjk

编辑

执行vector时间为 : 98毫秒!

List.size() : 100000

执行的总数对,说下同步锁没有丢数据。

在来看看copyOnWriteArrayList执行效果:

0f9hvHWRrXc

编辑

执行copyOnWriteArrayList时间为 : 5951毫秒!

List.size() : 100000

运行后数据比较:

运行的类

运行时长

运行结果

ArrayList

112毫秒

93266

Vector

98毫秒

100000

copyOnWriteArrayList

5951毫秒

100000

从上面表格中我们可以看出非安全线程的容器会丢数据。使用copyOneWriteArrayList耗时很长。那是因为每次运行都要copyof一份。

总结

copyArrayList(这里凯哥就简写了):是读写分离的。在写的时候会复制一个新的数组来完成插入和修改或者删除操作之后,再将新的数组给array.读取的时候直接读取最新的数据。

因为在写的时候需要向主内存申请控件,导致写操作的时候,效率非常低的(虽然在操作时候比较慢得,但是在删除或者修改数组的头和尾的时候还是很快的。因为其数据结构决定查找头和尾快,而且执行不需要同步锁)

从上面表中,可以看出copyArrayList虽然保证了线程的安全性,但是写操作效率太low了。但是相比Vector来说,在并发安全方面的性能要比vector好;

CopyArrayList和Vector相比改进的地方:

Vector是在新增、删除、修改以及查询的时候都使用了Synchronized关键字来保证同步的。但是每个方法在执行的时候,都需要获取到锁,在获取锁等待的过程中性能就会大大的降低的。

CopyArrayList的改进:只是在新增和删除的方法上使用了ReentrantLock锁进行(这里凯哥就不截图源码了,自己可以看看源码)。在读的时候不加锁的。所以在读的方面性能要不vector性能要好。

所以,CopyArrayList支持读多写少的并发情况

CopyOnWriteArrayList的使用场景:

由于读操作不加锁,增删改三个操作加锁的,因此适用于读多写少的场景,

局限性:因为读的时候不加锁的,读的效率和普通的arrayList是一样的。但是请看读操作:

0f9hvI6KnNg

编辑

0f9hvIcZqMK

编辑

在get的时候array使用的是volatile修饰的。是内存可见的。所以可以说copyArrayList在读的时候不会出现arrayList读取到脏数据的问题。

Get(i)方法比较如下:

0f9hvJ9EyUC

编辑


附件:arrayList、vector、copyOnwriteArrayList比较的代码:

public static void main(String[] args) {
//使用线程不安全的arrayList
// List<String> arryList = new ArrayList<>();
//使用vector
// List<String> arryList = new Vector<>();


//使用copyOnWriteArrayList
List<String> arryList = new CopyOnWriteArrayList<>();

Random random = new Random();
Thread [] threadArr = new Thread[100];
CountDownLatch latch = new CountDownLatch(threadArr.length);
Long beginTime = System.currentTimeMillis();
for(int i = 0;i<threadArr.length;i++){
threadArr[i] = new Thread(new Runnable() {
@Override
public void run() {
for(int j = 0; j < 1000; j++){
try {
arryList.add("value" + random.nextInt(100000));
catch (Exception e) {

}
}
latch.countDown();
}
});
}
for(Thread t : threadArr){
t.start();
}
try {
latch.await();
catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("执行copyOnWriteArrayList时间为 : " + (endTime-beginTime) + "毫秒!");
System.out.println("List.size() : " + arryList.size());
}


おすすめ

転載: blog.51cto.com/kaigejava/2479183