CoreJava基础之多线程(线程安全的集合类,ForkJoin框架)

1.线程安全的集合类

利用CAS算法 比较交换算法  无锁算法

(1)CopyOnWriteArrayList

利用复制数组的方式实现数据的写操作,读操作不用加锁

(适用于读操作频率远高于写操作的情况)

(2)ConcurrenHashMap(since 1.5)

实现方法:

JDK5-7:分段锁  将HashMap分割成16段,每段(segment)独立加锁

JDK8:使用CAS无锁算法,使用循环比较算法

(3)ConcurrentLinkedQueue

利用CAS算法,实现线程安全

offer():放入

poll():拿出

2.原子操作数据类型 (避免出现线程的不安全)

AtomicInteger 原子整数

AtomicBoolean原子布尔

AtomicLong原子长整数 等。。。

以上原子操作数所在java.lang.Number中

3.ForkJoin框架(since 1.7)

核心思想:利用递归将任务分解为若干个子任务,交给多线程去并发处理

用途:多用于多核cpu并发

继承类:RecursiveAction(无返回值)、RecursiveTask(有返回值)

任务代码:compute()方法 

ForkJoinPool:线程池  固定的线程数量:cpu的核数

工作窃取算法(早干完替耗时长的做任务):

当一个cpu内核结束所有任务时,会从其他的cpu内核的任务队列中“窃取”一个任务来执行,返回最大的并发性能。

(1)ForkJoinAction(代码实现)

package review.test;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public class ForkJoinActionTest01 {
	public static void main(String[] args) {
		String[] data = new String[10000];
		for (int i = 0; i < data.length; i++) {
			data[i] = "abcd" + i;
		}
		ForkJoinPool fjp = new ForkJoinPool();
		RecursiveAction ra = new NewAction(data ,0 , data.length);
		fjp.invoke(ra);
	}
}
class NewAction extends RecursiveAction{
	String[] data;
	int start;
	int end;
	public NewAction(){}
	public NewAction(String[] data,int start,int end){
		this.data = data;
		this.start = start;
		this.end = end;
	}
	public void compute(){
		if(end - start <= 100){
			for (int i = start ; i < end; i++) {
				data[i].toUpperCase();
			}
		}else{
			int middle = (start + end)/2;
			NewAction leftAction = new NewAction(data,start,middle);
			NewAction rightAction = new NewAction(data,middle, end);
			leftAction.fork();
			rightAction.compute();
			leftAction.join();
		}
	}
} 

(2)ForkJoinTask(代码实现)

package review.test;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

public class ForkJoinTaskTest01 {
	public static void main(String[] args) {
		int[] data = new int[5000];
		for (int i = 0; i < data.length; i++) {
			data[i]+=100+i;
		}
		ForkJoinPool pool = new ForkJoinPool();
		Integer result = (Integer) pool.invoke(new NewTask(data,0,data.length));
		System.out.println(result);
		pool.shutdown();
	}
}
class NewTask extends RecursiveTask{
	int[] data;
	int start;
	int end;
	public NewTask(){}
	public NewTask(int[] data,int start,int end){
		this.data = data;
		this.start = start;
		this.end = end;
	}
	public Integer compute(){
		if(end - start <= 100){
			int max = data[0];
			for (int i = 0; i < data.length; i++) {
				if(data[i] > max){
					max = data[i];
				}
			}return max;
		}else{
			int middle = (start + end)/2;
			NewTask leftTask = new NewTask(data,start,middle);
			NewTask rightTask = new NewTask(data,middle,end);
			leftTask.fork();
			Integer rightResult = rightTask.compute();
			Integer leftResult = (Integer) leftTask.join();
			if(rightResult > leftResult){
				return rightResult;
			}else{
				return leftResult;
			}
		}
		
	}
}

4.等待通知机制  (线程间通信)

Object类:定义了wait() notify() notifyAll()

①wait():必须在对o加锁的同步代码块中,对o调用wait()

线程会释放其拥有的所有锁标记

线程会阻塞在对象o的等待队列中

②notify()/notifyall():

必须在对o加锁的同步代码块中,对o调用notify()/notifyAll()

线程会从o的等待队列中,释放一个或者全部线程

package day27;

public class TestWaitNotify {

	public static void main(String[] args) throws Exception{
		Object o = new Object();
		
		System.out.println("main 1");
		
		Thread t = new Thread(){
			public void run(){
				synchronized (o) {
					System.out.println("thread 1");
					o.notify();
					System.out.println("thread 2");
				}
			}
		};
		t.start();
		
		synchronized (o) {
			o.wait();
			System.out.println("main 2");
		}
		
	}

}

5.生产者消费者问题

当生产者无法生产时,消费者等待

当消费者无法消费时,生产者等待

BlockingQueue  Queue接口的子接口   阻塞队列 接口

1.ArrayBlockingQueue  有界队列

当消费者无法消费时会阻塞,当生产者无法生产时会阻塞

2.LinkedBlockingQueue 无界队列

当消费者无法消费时会阻塞

package day27;
public class TestProducerConsumer {
	public static void main(String[] args) {
		MyStack stack = new MyStack();

		Thread t1 = new Thread(){
			public void run(){
				for(int i = 1 ; i <= 100 ; i++){
					stack.push("A"+i);
					stack.print();
				}
			}
		};
		t1.start();
		
		Thread t2 = new Thread(){
			public void run(){
				for(int i = 1 ; i <= 100 ; i++){
					stack.pop();
					stack.print();
				}
			}
		};
		t2.start();
	}
}

class MyStack{
	private String[] data = new String[5];
	private int index;
	
	public synchronized void push(String str){
		while(data.length == index){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		System.out.print(str+" pushed into stack  ");
		data[index] = str;
		index++;
		
		this.notifyAll();
	}
	public synchronized void pop(){
		while(index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		index--;
		System.out.print(data[index]+" poped out of stack   ");
		data[index] = " ";
		
		this.notifyAll();
	}
	
	public void print(){
		for(int i = 0 ; i < data.length; i++) System.out.print(data[i]+"   ");
		System.out.println();
	}
}

5.多线程自动启用流

parallelstream()

等同于:toStream()

基于Fork-join框架

面试题:

wait()与sleep()的区别:

wait会释放锁标记

sleep不会释放锁标记

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,让我为您解答关于entityframework core多线程安全添加数据的问题。 首先,为了保证多线程添加数据的安全性,我们需要采用下列方法之一: 1. 使用隔离级别为Serializable的数据库事务,这种隔离级别会锁定所有涉及的资源,直到事务完成,可以避免多个线程之间同时访问同一资源的问题。 2. 使用线程同步机制,比如使用lock关键字保护代码块,避免多个线程同时访问同一资源的问题。 在 Code First 设计模式中,我们可以使用 DbSet<TEntity> 类来代表一个实体集,从而方便地对实体对象进行各种操作。 在多线程环境下,我们应该创建不同的 DbContext 实例,并且别忘了使用 using 语句来自动释放资源。下面是一个使用 Code First 设计模式添加实体的多线程示例: ``` csharp public async Task AddEntityAsync<TEntity>(TEntity entity) where TEntity : class { using (var db = new MyDbContext()) { try { await db.Database.BeginTransactionAsync(IsolationLevel.Serializable); await db.Set<TEntity>().AddAsync(entity); await db.SaveChangesAsync(); await db.Database.CommitTransactionAsync(); } catch(Exception e) { await db.Database.RollbackTransactionAsync(); throw e; } } } ``` 在上面的代码中,我们使用了 IsolationLevel.Serializable 隔离级别来保证事务的粒度,同时使用 try..catch..finally 语句来保证事务的完整性,即事务在出现异常时回滚。 希望以上答案可以帮助您解决问题,谢谢。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员巨轮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值