collections源碼
A. java的List如何實現線程安全
Java的List如何實現線程安全?
Collections.synchronizedList(names);效率最高,線程安全
Java的List是我們平時很常用的集合,線程安全對於高並發的場景也十分的重要,那麼List如何才能實現線程安全呢 ?
加鎖
首先大家會想到用Vector,這里我們就不討論了,首先討論的是加鎖,例如下面的代碼
public class Synchronized{
private List<String> names = new LinkedList<>();
public synchronized void addName(String name ){
names.add("abc");
}
public String getName(Integer index){
Lock lock =new ReentrantLock();
lock.lock();
try {
return names.get(index);
}catch (Exception e){
e.printStackTrace();
}
finally {
lock.unlock();
}
return null;
}
}
synchronized一加,或者使用lock 可以實現線程安全,但是這樣的List要是很多個,代碼量會大大增加。
java自帶類
在java中我找到自帶有兩種方法
CopyOnWriteArrayList
CopyOnWrite 寫入時復制,它使一個List同步的替代品,通常情況下提供了更好的並發性,並且避免了再迭代時候對容器的加鎖和復制。通常更適合用於迭代,在多插入的情況下由於多次的復制性能會一定的下降。
下面是add方法的源代碼
public boolean add(E e) {
final ReentrantLock lock = this.lock; // 加鎖 只允許獲得鎖的線程訪問
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
// 創建個長度加1的數組並復制過去
Object[] newElements = Arrays.Of(elements, len + 1);
newElements[len] = e; // 賦值
setArray(newElements); // 設置內部的數組
return true;
} finally {
lock.unlock();
}
}
Collections.synchronizedList
Collections中有許多這個系列的方法例如
主要是利用了裝飾者模式對傳入的集合進行調用 Collotions中有內部類SynchronizedList
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
static class SynchronizedCollection<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 3053995032091335093L;
final Collection<E> c; // Backing Collection
final Object mutex; // Object on which to synchronize
這里上面的mutex就是鎖的對象 在構建時候可以指定鎖的對象 主要使用synchronize關鍵字實現線程安全
/**
* @serial include
*/
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
這里只是列舉SynchronizedList ,其他類類似,可以看下源碼了解下。
測試
public class Main {
public static void main(String[] args) {
List<String> names = new LinkedList<>();
names.add("sub");
names.add("jobs");
// 同步方法1 內部使用lock
long a = System.currentTimeMillis();
List<String> strings = new CopyOnWriteArrayList<>(names);
for (int i = 0; i < 100000; i++) {
strings.add("param1");
}
long b = System.currentTimeMillis();
// 同步方法2 裝飾器模式使用 synchronized
List<String> synchronizedList = Collections.synchronizedList(names);
for (int i = 0; i < 100000; i++) {
synchronizedList.add("param2");
}
long c = System.currentTimeMillis();
System.out.println("CopyOnWriteArrayList time == "+(b-a));
System.out.println("Collections.synchronizedList time == "+(c-b));
}
}
兩者內部使用的方法都不一樣,CopyOnWriteArrayList內部是使用lock進行加鎖解鎖完成單線程訪問,synchronizedList使用的是synchronize
進行了100000次添加後時間對比如下:
可以看出來還是使用了synchronize的集合工具類在添加方面更加快一些,其他方法這里篇幅關系就不測試了,大家有興趣去試一下。
B. 求大神翻譯這段源碼
使用UnityEngine;
using UnityEngine.UI;
使用unityengine.ui;
using UnityEngine.EventSystems;
使用unityengine.eventsystems;
using System.Collections;
使用系統集合;
using System.Collections.Generic;
使用system.collections.generic;
public class PanelManager : MonoBehaviour {
公共課panelmanager:MonoBehaviour {
public Animator initiallyOpen;
initiallyopen公共動畫;
public int m_OpenParameterId;
public int m_openparameterid;
public Animator m_Open;
m_open公共動畫;
public GameObject m_PreviouslySelected;
公共對象m_previouslyselected;
const string k_OpenTransitionName = "Open";
const string k_opentransitionname =「開放」;
const string k_ClosedStateName = "Closed
const string k_closedstatename =「封閉
我在做項目的時候需要將文件進行壓縮和解壓縮,於是就從http://www.icsharpcode.net下載了關於壓縮和解壓縮的源碼,但是下載下來後,面對這么多的代碼,一時不知如何下手。只好耐下心來,慢慢的研究,總算找到了門路。針對自己的需要改寫了文件壓縮和解壓縮的兩個類,分別為ZipClass和UnZipClass。其中碰到了不少困難,就決定寫出來壓縮和解壓的程序後,一定把源碼貼出來共享,讓首次接觸壓縮和解壓縮的朋友可以少走些彎路。下面就來解釋如何在C#里用http://www.icsharpcode.net下載的SharpZipLib進行文件的壓縮和解壓縮。
首先需要在項目里引用SharpZipLib.dll。然後修改其中的關於壓縮和解壓縮的類。實現源碼如下:
/// <summary>
/// 壓縮文件
/// </summary>
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.GZip;
namespace Compression
{
public class ZipClass
{
public void ZipFile(string FileToZip, string ZipedFile ,int CompressionLevel, int BlockSize)
{
//如果文件沒有找到,則報錯
if (! System.IO.File.Exists(FileToZip))
{
throw new System.IO.FileNotFoundException("The specified file " + FileToZip + " could not be found. Zipping aborderd");
}
System.IO.FileStream StreamToZip = new System.IO.FileStream(FileToZip,System.IO.FileMode.Open , System.IO.FileAccess.Read);
System.IO.FileStream ZipFile = System.IO.File.Create(ZipedFile);
ZipOutputStream ZipStream = new ZipOutputStream(ZipFile);
ZipEntry ZipEntry = new ZipEntry("ZippedFile");
ZipStream.PutNextEntry(ZipEntry);
ZipStream.SetLevel(CompressionLevel);
byte[] buffer = new byte[BlockSize];
System.Int32 size =StreamToZip.Read(buffer,0,buffer.Length);
ZipStream.Write(buffer,0,size);
try
{
while (size < StreamToZip.Length)
{
int sizeRead =StreamToZip.Read(buffer,0,buffer.Length);
ZipStream.Write(buffer,0,sizeRead);
size += sizeRead;
}
}
catch(System.Exception ex)
{
throw ex;
}
ZipStream.Finish();
ZipStream.Close();
StreamToZip.Close();
}
public void ZipFileMain(string[] args)
{
string[] filenames = Directory.GetFiles(args[0]);
Crc32 crc = new Crc32();
ZipOutputStream s = new ZipOutputStream(File.Create(args[1]));
s.SetLevel(6); // 0 - store only to 9 - means best compression
foreach (string file in filenames)
{
//打開壓縮文件
FileStream fs = File.OpenRead(file);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
ZipEntry entry = new ZipEntry(file);
entry.DateTime = DateTime.Now;
// set Size and the crc, because the information
// about the size and crc should be stored in the header
// if it is not set it is automatically written in the footer.
// (in this case size == crc == -1 in the header)
// Some ZIP programs have problems with zip files that don't store
// the size and crc in the header.
entry.Size = fs.Length;
fs.Close();
crc.Reset();
crc.Update(buffer);
entry.Crc = crc.Value;
s.PutNextEntry(entry);
s.Write(buffer, 0, buffer.Length);
}
s.Finish();
s.Close();
}
}
}
現在再來看看解壓文件類的源碼
/// <summary>
/// 解壓文件
/// </summary>
using System;
using System.Text;
using System.Collections;
using System.IO;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using System.Data;
using ICSharpCode.SharpZipLib.BZip2;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using ICSharpCode.SharpZipLib.GZip;
namespace DeCompression
{
public class UnZipClass
{
public void UnZip(string[] args)
{
ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]));
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
string directoryName = Path.GetDirectoryName(args[1]);
string fileName = Path.GetFileName(theEntry.Name);
//生成解壓目錄
Directory.CreateDirectory(directoryName);
if (fileName != String.Empty)
{
//解壓文件到指定的目錄
FileStream streamWriter = File.Create(args[1]+theEntry.Name);
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
streamWriter.Close();
}
}
s.Close();
}
}
}
有了壓縮和解壓縮的類以後,就要在窗體里調用了。怎麼?是新手,不會調用?Ok,接著往下看如何在窗體里調用。
首先在窗體里放置兩個命令按鈕(不要告訴我你不會放啊~),然後編寫以下源碼
/// <summary>
/// 調用源碼
/// </summary>
private void button2_Click_1(object sender, System.EventArgs e)
{
string []FileProperties=new string[2];
FileProperties[0]="C:\\unzipped\\";//待壓縮文件目錄
FileProperties[1]="C:\\zip\\a.zip"; //壓縮後的目標文件
ZipClass Zc=new ZipClass();
Zc.ZipFileMain(FileProperties);
}
private void button2_Click(object sender, System.EventArgs e)
{
string []FileProperties=new string[2];
FileProperties[0]="C:\\zip\\test.zip";//待解壓的文件
FileProperties[1]="C:\\unzipped\\";//解壓後放置的目標目錄
UnZipClass UnZc=new UnZipClass();
UnZc.UnZip(FileProperties);
}
好了,到此為止,如何壓縮和解壓縮的類都已經完成了,需要的朋友直接拿走調吧。
D. Kotlin常用Collection集合操作整理
本篇記錄了 Kotlin 常用集合的相關操作,用以熟練使用 Kotlin 里的相關集合。集合介面與相關函數位於 kotlin.collections 包中。
Kotlin 標准庫提供了基本集合類型的實現: Set、List 以及 Map。 一對介面代表每種集合類型:
其中灰色是不可變集合,黃色是可變集合。 Iterator 意為迭代器, Collection 是只讀介面,而 MutableCollection 是一個具有寫操作的 Collection 介面:
List< T> 以指定的順序存儲元素,並提供使用索引訪問元素的方法。從第一個元素索引0 到最後一個元素索引 (list.size - 1) 為止。 List 的默認實現是 ArrayList 。
執行結果會轉化為 Map :
Set 內部是用 Map 實現的, Set 相關的實現詳見: Java Collection系列之:HashSet、LinkedHashSet、TreeSet的使用及源碼解析
Map<K, V> 不是 Collection 介面的繼承者;但是它也是 Kotlin 的一種集合類型。 Map 存儲 鍵-值 對(或 條目);鍵是唯一的,但是不同的鍵可以與相同的值配對。 Map 介面提供特定的函數進行通過鍵訪問值、搜索鍵和值等操作。 Map 相關的實現詳見: Java Collection系列之HashMap、ConcurrentHashMap、LinkedHashMap的使用及源碼分析
Iterable 處理包含多個步驟時,每個處理步驟完成並返回其結果——中間集合,然後在此集合上執行後續步驟。 Sequence 序列僅當請求整個處理鏈的結果時才進行實際計算: Sequence 對每個元素逐個執行所有處理步驟。
結論 :序列可避免生成中間步驟的結果,從而提高了整個集合處理鏈的性能。 但是,序列的延遲性質增加了一些開銷,這些開銷在處理較小的集合或進行更簡單的計算時可能很重要。 因此,應該同時考慮使用 Sequence 與 Iterable ,並確定在哪種情況更適合。
執行結果:
執行結果:
上述序列中, Sequence 處理需要 18 個步驟, Iterable 需要 23 個步驟來執行列表操作,上述示例參見 Sequence序列操作 。
創建與現有集合具有相同元素的集合,可以使用復制操作,例如 toList()、toMutableList()、toSet() 等等。標准庫中的集合復制操作創建了具有相同元素引用的 淺復制 集合。 因此, 對集合元素所做的更改會反映在其所有副本中,如果對源集合進行添加或刪除元素,則不會影響副本 。
排序主要使用 Comparable 及 Comparator 。其中 Comparable 可以理解為是內部排序, Comparator 是外部排序。
集合排序示例: