❶ java多线程同时向一个数组arraylist添加元素,遍历这个集合
ArrayList集合是不行的,如果多线程同时添加元素,有可能产生线程安全问题,程序也有可能报错。
例如:一个线程正准备往进去写数据,突然切到另一个线程它先写了进入,在切回来这个线程并不知道这个位置已经写入了数据,所以它还是会傻傻的写入数据,这样另一个线程的数据就被覆盖了。如果是一边添加 ,一边遍历的话程序会产生异常。
所以要用onwritearraylist是最好的选择,但是注意的是,添加元素时它的性能不是很好 。
❷ 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的集合工具类在添加方面更加快一些,其他方法这里篇幅关系就不测试了,大家有兴趣去试一下。
❸ java涓鍒╃敤澶氱嚎绋嫔规暟缁勫艰繘琛屼慨鏀癸纴涓轰粈涔堜笉鏄𨱍宠佺殑缁撴灉锛
骞朵笉鏄杈揿嚭涓崭细鍑虹幇浣犳兂瑕佺殑锛岋纴澶氩幓镓句笅绾跨▼鏂归溃镄勮祫鏂欑湅鐪嬶纴锛
娌℃湁寰楀埌浣犳兂瑕佺殑鍊兼槸锲犱负绾跨▼镓ц岄‘搴忛犳垚镄勶纴锛岄栧厛浣犺繖涓绋嫔簭杩愯岃捣𨱒ユ诲叡链変笁涓绾跨▼
涓荤嚎绋嬶纴绾跨▼t1锛岀嚎绋媡2
瀹为檯涓奵pu澶勭悊绾跨▼镄勬椂鍊椤苟涓嶆槸鐪熸g殑钖屾椂杩涜岋纴钥屾槸镓ц屾煇涓绾跨▼涓娈垫椂闂达纴铹跺悗鍦ㄦ墽琛屽叾浠栫嚎绋嬩竴娈垫椂闂达纴涓鐩磋繖镙峰惊鐜涓嫔幓
绾跨▼镄勬墽琛岄‘搴忔槸涓嶅畾镄勶纴涓嶆槸姣忔¢兘鏄痶1鍏堬纴t2钖庯纴镓ц岄‘搴忓拰绾跨▼镄勪紭鍏堢骇链夊叧绯伙纴鍦ㄧ嚎绋嬩紭鍏堢骇閮界浉钖岀殑𨱍呭喌涓嬶纴镓ц屾潈鏄闅忔満鍒嗛厤镄勶纴锛屼篃灏辨槸璇村彲鑳借繖娆t1鍏堟墽琛岋纴涓嬫″嵈鏄痶2鍏堟墽琛岋纴镓浠ヤ綘瑕佺殑缁撹炬槸鍙鑳藉嚭鐜扮殑锛岋纴浣嗘槸涓嶆槸姣忔¢兘鏄浣犳兂瑕佺殑缁撹撅纴锛岃屼笖涓鑸𨱍呭喌涓嫔氱嚎绋嫔苟鍙戣块梾鏁版嵁镄勬椂鍊欙纴鎴戜滑閮戒细锅氩悓姝ュ勭悊锛岄伩鍏嶆暟鎹鍑虹幇绱娄贡锛
褰扑富绾跨▼闅忔満鍒版墽琛屾潈锛岄偅涔堜富绾跨▼鍏堟墽琛岋纴镓浠ヨ繖镞跺栾幏鍙栧埌镄勬暟鎹灏卞彲鑳芥槸铡熷嬫病鏀瑰彉镄勫硷纴锛屽綋t1鎴杢2闅忔満鍒版墽琛屾潈锛岄偅涔堣幏鍙栫殑鏁版嵁灏辨槸琚淇鏀硅繃镄勶纴锛屼絾鏄淇鏀圭殑缁撴灉鏄镞犺勫緥镄勶纴锛
涓嬮溃鏄甯浣犱慨鏀逛简涓嬬殑锛岋纴濡傛灉杩树笉鏄浣犵殑缁撴灉锛屽彲浠ユ妸Thread.sleep(镞堕棿)涓镄勬椂闂磋皟澶т竴镣
publicclassHappy
{
staticintarr[]={1,2,3,4,5};
publicstaticvoidresult()
{
Bolg1p1=newBolg1(arr);
Bolg2p2=newBolg2(arr);
Threadt1=newThread(p1);
Threadt2=newThread(p2);
t1.start();
t2.start();
}
publicstaticvoidmain(String[]args)throwsException
{
Happy.result();
Thread.sleep(1000);//𨱌傚仠涓荤嚎绋1绉掞纴锛岀瓑寰呭叾浠栫嚎绋嬫墽琛
for(intm:arr)
{
System.out.println(m+"");
}
}
}
classBolg1implementsRunnable
{
int[]arr;
publicBolg1(int[]arr)
{
this.arr=arr;
}
publicvoidrun()
{
for(inti=0;i<arr.length;i+=2)
{
arr[i]=10;
}
}
}
classBolg2implementsRunnable
{
int[]arr;
publicBolg2(int[]arr)
{
this.arr=arr;
}
publicvoidrun()
{
for(intj=1;j<arr.length;j+=2)
{
arr[j]=11;
}
}
}
❹ java中怎么用多个线程同时对一个文件读取,最终将文件内容保存到一个字节数组中去呢
多线程读取文件在一块硬盘上没用,瓶颈在硬盘I/O,而不在CPU和内存。读取文件时,CPU不用复杂的计算工作,只是数据传输而已,多线程反而造成磁头来回移动,效率不高。如果是两块以上的硬盘,可以用不同的线程访问不同的硬盘,效率比单线程要高
而且多线程操作同一文件除了效率还会有多线程问题,多个线程同时往数组里存数据还会有线程安全问题,如果不同步处理读取的文件就是错误的。
如果读取的话只能设置每个线程各自读取偏 移量
读取文件大小(比如大小是200K)。 2,启动5个线程,第一个线程读到40,第二个线程跳过40在读到80,总之得合理安排好各个线程读取的大小。这样才能不重复读取。大数据处理框架maprece原理和此类似
❺ JAVA开启三个线程,去读取数组中的数据不能重复
set中是不能存在重复数的。
这个可以通过修改数据的时间来判断。例如:表中有个字段读取时间。当这个客户读取10条数据的时候,更新读取时间为当前时间。然后下个客户读取的时候,判断时间在半个小时内,没有更新的数据。就OK了。