并发编程(1)

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/weixin_43014205/article/details/86520919

当若干个线程共享主存区的资源时,将主存区的资源复制到自己的线程中使用,使用完毕后放回主内存,这时会产生线程安全问题。

如果是各个线程用自己的资源,则不会。

JVM内存模型:可见性,原子性。

1.线程安全额概念:当多个线程访问某一个类、对象或方法时,这个类、对象或方法都能表现出与单线程执行时一致的行为,那么就是线程安全的。

2.线程安全问题都是由全局变量及静态变量引起的。

3.每个线程中对全局变量、静态变量只有读操作,没有写操作,一般来说这个全局变量是线程安全的,若多个线程同时执行写操作,一般都要考虑线程同步。

Synchronized

Synchronized方法执行方式:

首先尝试获得锁

如果获得锁,则执行Synchronized的方法体内容

如果无法获得锁则等待,且不断尝试去获得锁,一旦锁被释放,则多个线程或同时去尝试获得锁,造成锁竞争问题。

锁竞争问题,在高并发、线程数量高时会引起CPU占用居高不下,或直接宕机

类锁和对象锁

Synchronized作用在非静态方法上代表的是对象锁,一个对象一把锁,多个对象之间不会发生锁竞争。

Synchronized作用在静态方法上则升级为类锁,所有对象共享一把锁,存在锁竞争。

同步和异步

同步:必须等待方法执行完毕后,才能向下执行,共享资源访问的时候,为了保证线程安全,必须同步。

异步:不用等待其他方法执行完毕,即可立即执行,例如Ajax异步。

对象锁的同步和异步

对象锁只针对Synchronized修饰的方法生效,对象中的所有Synchronized都会同步执行,而非Synchronized方法异步执行

脏读

多个线程访问同一个资源,在一个线程修改数据的过程中,有另外的线程来读取数据,就会引起脏读。

为了避免脏读,一定要保证数据修改的操作的原子性,也就是说,不仅要对数据的修改方法加锁,也要对读数据的方法加锁,这样才能做到对读取操作的同步控制。

Synchronized锁重入

同一个对象内得多个Synchronized方法可以锁重入

A方法时Synchronized的    B方法也是Synchronized的

在调用A的过程中调用B      并不会发生死锁,会正常执行

父子类也可以锁重入      在子类的Synchronized方法中调用父类的Synchronized方法    也不会死锁

抛出异常释放锁

一个线程在获得锁之后执行操作,发生错误抛出异常,则自动释放锁

可以利用抛出异常,主动释放锁

程序异常时防止资源被死锁、无法释放

异常释放锁可能导致数据不一致

 

Synchronized代码块

可以达到更精细的控制

当前对象锁

类锁

任意对象锁

总结:同类型锁之间互斥,不同类型锁直接互不干扰

锁失效

不要在线程中修改锁对象的引用,引用会引起锁失效

例如给一个字符串对象加锁,在线程中修改了字符串,则锁会失效,因为修改了字符串,获得的是一个新的地址

但是在线程中修改锁对象的属性不会引起锁失效,例如修改一个person对象的名字,只改变了其属性,但对象地址没变,不会引起线程安全问题

总结:线程A修改了对象锁的引用,则线程B实际得到了新的对象锁,而不是锁被释放了,因此引起了线程安全问题。

并发与死锁

指两个或者两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞现象,若无外力作用,他们永远不会被推进下去。

线程之间通讯

每个线程都是独立运行的个体,线程通讯能让多个线程协同工作

Object类中的wait\notify方法可以实现线程间的通讯

wait\notify必须和Synchronized一同使用

wait释放锁    notify只是发出通知 但不释放锁

猜你喜欢

转载自blog.csdn.net/weixin_43014205/article/details/86520919
今日推荐