多线程(六)——解决线程不安全的方法

1.解决线程不安全的方法:

锁机制(内置锁/监视器锁synchronized关键字)

1) 同步代码块

synchronized( 同步锁){    //同步锁:同步监听对象/ 同步监听器 /互斥锁

需要同步操作的代码(临界区)

}

对象的同步锁只是一个概念,可以想象在对象上标记 一个锁

java程序运行可以使用任何对象作为同步监听对象,但是一般我们将当前i并发访问的共同资源(多个线程同步共享的资源对象)作为同步监听对象。

  • 注意:在任何时候,只允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他线程只能在外面等

2)同步方法

//作为方法的修饰符
public synchronized void method(){
}

使用synchronized修饰的方法叫做同步方法,保证该线程执行该方法的时候,其他线程只能等着。

同步锁:
1.非static方法,同步锁是this,当前对象
2.static方法,使用当前方法所在类的字节码对象(Apple.class)是同步锁

注意:

  • synchronized不能修饰run方法,修饰之后,一个线程就执行了所有的功能,线程出现串行,相当于单线程。
    解决方法:将需要同步的 代码定义在一个新的方法中,并且该方法用synchronized修饰,再在run方法中调用该新的方法即可

synchronized提高安全性,但是性能降低了,使用时尽量减小它的作用域。

例如:stringBuffer和StringBuilder的区别,stringBuffer的方法全都加了synchronized修饰。

  • synchronized 锁的到底是什么?
    锁的是具体一个对象中的内置锁。
  • 如何通过java的语法找到对象?
    普通方法:this指向的对象/当前对象
    静态方法:类对象
    代码块:括号中引用指向的对象

锁的是什么?
需要锁同一个对象,否则相当于没锁

都在加锁,锁的是同一个对象-互斥
加锁只看对象,不看方法

volatile

变量修饰符,只能修饰属性/静态属性

主要作用:
1.保证被修饰变量的可见性-主内存与工作内存
2.保证一定的顺序性
3.不会导致线程切换
4.保证long/double的原子性
即long x = 10L 保证其为原子性

2. 加锁后的互斥行为判断:

互斥行为的产生必须:
1.竞争双方都有请求锁的行为
2.请求的是同一把锁(根据引用找),与方法无关

通过以下的例子来理解是否会发生互斥行为

class A {
    synchronized method();
    synchronized static staticMethod();
    noSyncMethod();
    noSyncStaticMethod();
    synchronized method2();
}

A p = new A();
A q = new A();
A s = p;

发生互斥行为:

AThreadBThread是否会互斥
p.method()p.method
p.method()s.method()
p.method()p.staticMethod()不会
p.method()q.method()不会
p.method()p.noSyncMethod()不会
p.method()p.method2()
抢锁
  • 抢锁的前提是先抢CPU
  • 抢锁失败:
    1.状态从RUNNABLE修改为BLOCKED
    2.线程从就绪队列移动到该锁的阻塞队列上
    3.从开始请求锁到最终抢到锁,经历了沧海桑田

synchronized:保证了原子性/可见性/保证了一定的重排序结果
优点:基本有了它,线程能基本保证安全
缺点:效率低/不够灵活

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值