如何实现线程安全?

如何实现线程安全?,第1张

1: 加锁 利用Synchronized或者ReenTrantLock来对不安全对象进行加锁,来实现线程执行的串行化,从而保证多线程同时 *** 作对象的安全性,一个是语法层面的互斥锁,一个是API层面的互斥锁.

2: 非阻塞同步来实现绝派销线程安全。原理就是:通俗点讲,就是先进性 *** 作,如果没有其他线程争用共享数据,那 *** 作就成功了;如果共享数据有争用,产生冲突,那就再采取其他措施(最常见的措施就是不断地重试,直到成功为止)。这种方法需要硬件的支持,因为我们需要 *** 作和冲突检测这两个步骤具备原子性。通常这种指令羡链包括CAS SC,FAI TAS等。

3:线程本地化,一种无同步的方案并游,就是利用Threadlocal来为每一个线程创造一个共享变量的副本来(副本之间是无关的)避免几个线程同时 *** 作一个对象时发生线程安全问题

spring中管理的bean实例默认情况下是单例的[sigleton类型],就还有prototype类型

按其作用域来讲有sigleton,prototype,request,session,global session。

spring中的单例与设计模式里面的单例略有不同,设计模式的单例是在整个应用中只有一个实例,而spring中的单例是在一个IoC容器中就只有一个实例。

但spring中的单例也不会影响应用的并发访问,【不会出现各个线程之间的等待问题,或是死锁问题】因为大多数时候客户端都在访问我们应用中的业务对象,而这些业务对象并

没有做线腔滚喊程的并发限制,只是在这个时候我们不应该在业务对象中设置那些容易造成出错的成员变量,在并发访问时候这些成员变量将会是并发线程中的共享对象,那么这个时候

就会出现意外情况。

那么我们的Eic-server的所有的业务对象中的成员变量如,在Dao中的xxxDao,或controller中的xxxService,都会被多个线程共享,那么这些对象不会出现同步问题吗,比如会造

成数据库的插入,更新异常?

还有我们的实体bean,从客户端传递到后台的controller-->service-->Dao,这一个流程中,他们这些对象都是单例的,那么这些单例的对象在处理我们的传递到后台的实体bean不

会出问题吗?

答:[实体bean不是单例的],并没有交给spring来管理,每次我们都手动的New出来的【如EMakeType et = new EMakeType()】,所以即使是那些处理我们提交数据的业务处理类

是被多线程共享的,但是他们处理的数据并不是共享的,数据时每一个线程备和都有自己的一份,所以在数据这个方面是不会出现线程同步方面的问题的。但伍野是那些的在Dao中的

xxxDao,或controller中的xxxService,这些对象都是单例那么就会出现线程同步的问题。但是话又说回来了,这些对象虽然会被多个进程并发访问,可我们访问的是他们里面的方

法,这些类里面通常不会含有成员变量,那个Dao里面的ibatisDao是框架里面封装好的,已经被测试,不会出现线程同步问题了。所以出问题的地方就是我们自己系统里面的业务

对象,所以我们一定要注意这些业务对象里面千万不能要独立成员变量,否则会出错。

所以我们在应用中的业务对象如下例子;

controller中的成员变量List和paperService:

public class TestPaperController extends BaseController {

private static final int List = 0

@Autowired

@Qualifier("papersService")

private TestPaperService papersService

public Page queryPaper(int pageSize, int page,TestPaper paper) throws EicException{

RowSelection localRowSelection = getRowSelection(pageSize, page)

List<TestPaper>paperList = papersService.queryPaper(paper,localRowSelection)

Page localPage = new Page(page, localRowSelection.getTotalRows(),

paperList)

return localPage

}

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.copyOf(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 = 0i <100000i++) {

strings.add("param1")

}

long b = System.currentTimeMillis()

// 同步方法2 装饰器模式使用 synchronized

List<String>synchronizedList = Collections.synchronizedList(names)

for (int i = 0i <100000i++) {

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的集合工具类在添加方面更加快一些,其他方法这里篇幅关系就不测试了,大家有兴趣去试一下。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/bake/11979109.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-20
下一篇 2023-05-20

发表评论

登录后才能评论

评论列表(0条)

保存