java 线程的移动问题_java多线程编程之同步问题

1、原子性

我们都知道,原子一般都是不可分割的。在多线程环境中,如果能确保一个类中的所有操作都是原子性的,那么这个类肯定是线程安全的。比如,我们前面的那个计数器例子,value++是一个复合操作,它涉及到3个步骤:读取--修改--写入,首先要将值从寄存器读到内存中,然后进行修改,修改完毕再写回寄存器。这里存在一个竞争条件:必须基于之前的那个值,然后递增,如果前面的那个值已经失效了,那么肯定就有问题。

解决这个问题的一个办法是:将复合操作变为原子性。JDK 5.0以后已经添加了原子性的相关类,我们可以使用JDK提供的原子类解决这个问题,如:

publicclass Counter {

private AtomicInteger value = new AtomicInteger(0);

publicint getNext(){

returnvalue.incrementAndGet();

}

}

在实际情况中,尽可能的使用现有的线程安全类(如AtomicInteger)来管理类的状态。

2、加锁

原子性在只有一个状态的情况下,可以实现线程安全。但是如果一个类有多个状态的时候,即使把所有的成员变量都声明为原子性的,依然不是线程安全的,这是因为多个状态之间可能会有依赖关系,而原子性只能保证单个状态的线程安全。

当一个类的状态比较多,原子性解决不了的时候,就要使用加锁的机制了。锁本身分为很多种,最常见的就是内置锁,我先介绍一下内置锁的使用,后续再详细介绍其他锁的使用。

在讲到内置锁的时候,不得不提到synchronized关键字。synchronized用来对方法或代码块进行同步,synchronized本质上就是使用锁来进行同步的,这个锁通常是内置锁,当然也可以是其他对象的锁。synchronized有两种使用方法,下面简单介绍一下:

1)同步一个方法

首先要确认修饰的方法是static还是非static。如果是非static方法,那么使用这个对象的内置锁进行同步;如果是static方法,那么使用这个类的Class进行同步。

用synchronized修饰的方法,在进入之前会先获得一个锁,退出后会释放这个锁,在执行过程中其他线程必须等待,直到这个锁被释放掉。

2)同步一个代码块

用synchronized修饰一个用{}括起来的代码块,同时必须指定同步使用的是哪一个锁。由于java所有对象都有一个内置锁,synchronized后面可以跟一个对象,指定你需要在哪个对象上进行同步,如果需要在当前对象上同步,则使用this,比如:

publicclass Counter {

private   int      value;

publicint     getNext(){

synchronized(this) {

returnvalue++;

}

}

}

注意:由于使用synchronized会持有一个锁,因此必须确保synchronized同步的代码尽量少,从而保证运行的效率。如果代码比较多,执行比较耗时,会导致其他线程等待,从而影响到执行效率。

建议尽量不要用synchronized同步方法,除非这个方法本身代码比较少。尽量用synchronized来同步代码块,而且只同步那些需要同步的代码。换句话说,让synchronized同步的代码越少越好。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值