java线程安全是什么意思,JAVA-线程安全

程序都避免不了使用线程,但是当不同的线程同时操作同一个变量、同一个对象时,如果不进行控制,那么程序的结果就极大可能不是我们想要的。

例如:有一个变量a,初始值为0;

线程A、线程B都分别对变量a进行累加100次,每次增加1;

如果不加任何控制,那最后的结果就不会是200了。

这种时候,我们就需要对相应部分的代码进行控制,就是加个锁。

什么是锁?

①类锁

以一个类来作为锁,常见于单例模式,还有修饰静态的方法。

因为方法是静态的,也就是说这个类和方法不需要经过实例化就可以调用,所以如果要加锁控制,同样也不能要求实例化,所以叫类锁。

/**

* synchronized 内置🔒 JDK提供的 内部已经封装

*/

public class GPSEngine {

private static GPSEngine gpsEngine;

public static synchronized GPSEngine getInstance() {

if (gpsEngine == null) {

// Thread-1 释放CPU执行器 Thread-0来执行了 结果 new GPSEngine 此时Thread-1获得执行资格 有 new

gpsEngine = new GPSEngine();

}

return gpsEngine;

}

/*public static GPSEngine getGpsEngine() {

if (null == gpsEngine) {

synchronized (GPSEngine.class) { // 类锁 还没有new GPSEngine == 没有this

if (null == gpsEngine) {

gpsEngine = new GPSEngine();

}

}

}

return gpsEngine;

}*/

}

②对象锁

区别于类锁,对象锁就是用一个对象类作为锁。

/**

* synchronized 内置

*

* 类说明:synchronized的作用

*

* 对象锁

*

*/

public class SynTest {

private long count =0;

private Object obj = new Object(); // 作为一个锁 对象锁obj

private String str = new String(); // 作为一个锁 对象锁str

public long getCount() {

return count;

}

public void setCount(long count) {

this.count = count;

}

// count进行累加

public void incCount(){

// T1 T2

synchronized (obj){ // 使用一把锁

// T0 T1 T2 == 多个线程 并发问题

count++;

}

}

// count进行累加

// synchronized == 对象锁 == this

public synchronized void incCount2(){

count++;

}

// count进行累加

// this == 对象锁

public void incCount3(){

synchronized (this){

count++;

}

}

// 线程

private static class Count extends Thread{

private SynTest simplOper;

public Count(SynTest simplOper) {

this.simplOper = simplOper;

}

@Override

public void run() {

for(int i=0;i<10000;i++){

simplOper.incCount(); // count = count+10000

}

}

}

public static void main(String[] args) throws InterruptedException {

SynTest simplOper = new SynTest();

// 启动两个线程

Count count1 = new Count(simplOper);

Count count2 = new Count(simplOper);

count1.start();

count2.start();

Thread.sleep(50);

// 2w

System.out.println(simplOper.count);//20000

}

}

③显示锁

显示锁,其实就是自定义锁,就是说锁的行为可以由我们自己来自由控制。

而上面的类锁和对象锁,都是由synchronize来帮我们实现的,我们不需要管太多。

/**

* 使用显示锁的范式

*/

public class LockDemo {

private int count = 0;

// 内置锁 == this

private synchronized void test() {

}

// 内置锁 == LockDemo.class

private static synchronized void test2() {

}

private synchronized void test3() {

// 业务逻辑,无法被中断

}

// 声明一个显示锁之可重入锁 new 可重入锁

// 非公平锁

private Lock lock = new ReentrantLock();

public void incr(){

// 使用 显示锁 的规范

lock.lock();

try{

count++;

} finally { // 打死都要执行 最后一定会执行

lock.unlock();

}

}

// 可重入锁🔒 意思就是递归调用自己,锁可以释放出来

// synchronized == 天生就是 可重入锁🔒

// 如果是非重入锁🔒 ,就会自己把自己锁死

public synchronized void incr2(){

count++;

incr2();

}

public static void main(String[] args) {

LockDemo lockDemo = new LockDemo();

}

}

死锁是怎么造成的?

死锁就是程序被彻底锁住了,导致程序无法继续执行。

一般死锁的原因就是synchronize嵌套使用了,避免这种情况,基本就避免了死锁。

线程安全的应用场景

生产者消费者模式,就是很经典的例子。

而其中音视频的处理,就是其中之一,因为音频和视频我们需要达到同步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值