线程安全问题

一,线程不安全的原因

(1)线程是一个抢占式的执行模式(谁先谁后执行取决于系统的调度器的调度)

(2)多个线程对同一个资源进行修改(这取决于需求)

(3)修改操作不是原子性的(如果将修改操作打包成一个整体,禁止相互穿插进行,就可以保证线程安全  )

(4)内存可见性(编译器为了效率会优化省略很多重复的步骤 但是再多线程中就会出现问题)

(5)指令重排序(编译器再保证逻辑不变的前提下,为了让程序跑的更快,会对指令进行优化,重新排序,如果是再多线程中,这时就可能会出现很大的问题)

使修改操作是原子性的,和保证内存可见性,还有防止指令重排序 这三个是保证线程安全的主要手段

二,具体如何实施

(1)使用synchronized(监视器锁)关键字进行加锁

1.synchronized功能就是保证操作的原子性,同时禁止指令重排序和保证内存可见性。

他有两种用法:(1)对方法进行加锁    (2)对代码块进行加锁

进入代码块或调用方法,就加锁,出了代码块或方法调用结束,就解锁。

2.使用synchronized就相当于给操作加上了LOCK(LOCK操作的特性,只有一个线程能执行成功,如果第一个线程已经执行成功并且还未执行完毕,这时候另一个线程也尝试LOCK,就会进入阻塞,直到第一个线程执行UNLOCK释放锁)和UNLOCK指令,通过LOCK和UNLOCK指令就可以把一个操作的指令打包成一个原子的操作,不可以被别的线程穿插,同时synchronized也可以防止编译器进行,内存可见性和指令重排序的优化。

但是一旦使用了synchronized会使程序的运行效率大大降低,所以一旦代码里加锁了,这个代码基本上就注定与高性能无关了。

3.(1)修饰代码块synchronized(){},一般是对哪个对象进行加锁,()里就传入哪个对象。

 (2)修饰的是方法

//非静态方法这时候加锁的对象就是this
synchronized void add(){
    count++;
}

//静态方法这时候加锁的就是类对象(每个类都有一个类对象,全局唯一的)
synchronized static void add1(){
    count++;
}

3.如果嵌套加锁 就会造成死锁,第二个LOCK紧跟第一个LOCK,第二个LOCK需要第一个LOCK释放锁才能继续执行,第一个LOCK要等执行下去才能释放锁,但是执行到第二个LOCK执行不下去了。

不过synchronized不存在这种问题,它实现了可重入锁,它不是真正的加锁,它内部记录了当前这把锁是哪个线程持有的,如果加锁线程和持有锁线程是同一个,它就会把一个计数器++,如果再次加锁计数器就会再++,如果线程解锁,它也是把计数器--,直到计数器为0此时才释放锁。

(2)volatile

volatile起到的作用也是保证线程安全,它只保证内存可见性(每次必须都从内存中读取,不可以直接读工作内存(寄存器/缓存)),和禁止指令重排序,不保证原子性,所以主要用于读写同一个变量时。

 这个功能synchronized也可以完成但是volatile不涉及锁竞争,不涉及线程调度,会更加轻量,更高效。

(3)对象等待集

作用:协调多个线程之间的执行先后顺序。

waiting(等待)状态:join()保证两个线程按照一定的顺序来 可以保证谁先执行完, wait()它必须要再synchronized里使用还需要搭配notify()/notifyAll()来唤醒等待  它们也得写到synchronized里,调用notify()方法后并不会立即释放锁,得等到synchronized执行完之后才释放锁 否则就会报异常。

timed-waiting(超时等待):同上不过多了sleep(long)它们会设置一个时间,超过时间后还没有完成,就会自动唤醒等待。

其他:wait()和sleep()的区别

1. wait 之前需要请求锁(因为是wait只能在synchronized中使用否则会报异常),而wait执行时会先释放锁,等被唤醒时再重新请求锁。这个锁是 wait 对像上的 monitor lock(监视器锁synchronized)

2. sleep 是无视锁的存在的,即之前请求的锁不会释放,没有锁也不会请求。
3. wait Object 的方法
4. sleep Thread 的静态方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值