Java 中 ++ 操作符是线程安全的吗

高手有没有人讲详细点的,我想问一下,Java 中 ++ 操作符是线程安全的吗
最新回答
长发与酒

2024-09-29 05:30:21

总的结论:java是线程安全的,即对任何方法(包括静态方法)都可以不考虑线程冲突,但有一个前提,就是不能存在全局变量。如果存在全局变量,则需要使用同步机制。如下通过一组对比例子从头讲解:在多线程中使用静态方法会发生什么事?也就是说多线程访问同一个类的static静态方法会发生什么事?是否会发生线程安全问题?publicclassTest{publicstaticvoidoperation(){//dosomething}}事实证明只要在静态函数中没有处理多线程共享数据,就不存在着多线程访问同一个静态方法会出现资源冲突的问题。下面看一个例子:publicclassStaticThreadimplementsRunnable{@Overridepublicvoidrun(){//TODOAuto-generatedmethodstubStaticAction.print();}publicstaticvoidmain(String[]args){for(inti=0;i<100;i++){newThread(newStaticThread()).start();}}}publicclassStaticAction{publicstaticinti=0;publicstaticvoidprint(){intsum=0;for(inti=0;i<10;i++){System.out.print("step"+i+"isrunning.");sum+=i;}if(sum!=45){System.out.println("Threaderror!");System.exit(0);}System.out.println("sumis"+sum);}}实际执行的结果显示各个线程对静态方法的访问是交叉执行的,但是这并不影响各个线程静态方法print()中sum值的计算。也就是说,在此过程中没有使用全局变量的静态方法在多线程中是安全的,静态方法是否引起线程安全问题主要看该静态方法是否对全局变量(静态变量staticmember)进行修改操作。在多线程中使用同一个静态方法时,每个线程使用各自的实例字段(instancefield)的副本,而共享一个静态字段(staticfield)。所以说,如果该静态方法不去操作一个静态成员,只在方法内部使用实例字段(instancefield),不会引起安全性问题。但是,如果该静态方法操作了一个静态变量,则需要静态方法中采用互斥访问的方式进行安全处理。我们来看一下没有使用互斥访问的话会产生怎样的问题:publicclassStaticAction{publicstaticinti=0;publicstaticvoidincValue(){inttemp=StaticAction.i;try{Thread.sleep(1);}catch(Exceptione){e.printStackTrace();}temp++;StaticAction.i=temp;}}publicclassStaticThreadimplementsRunnable{@Overridepublicvoidrun(){//TODOAuto-generatedmethodstubStaticAction.incValue();}publicstaticvoidmain(String[]args){for(inti=0;i<100;i++){newThread(newStaticThread()).start();}try{Thread.sleep(1000);//预留足够的时间让上面的线程跑完}catch(Exceptione){e.printStackTrace();}System.out.println(StaticAction.i);}}实际运行结果显示i值为随机的数字。为了实现互斥访问,这时我们需要加入一个synchronized关键字。代码修改如下:publicclassStaticAction{publicstaticinti=0;publicsynchronizedstaticvoidincValue(){inttemp=StaticAction.i;try{Thread.sleep(1);}catch(Exceptione){e.printStackTrace();}temp++;StaticAction.i=temp;}}publicclassStaticThreadimplementsRunnable{@Overridepublicvoidrun(){//TODOAuto-generatedmethodstubStaticAction.incValue();}publicstaticvoidmain(String[]args){for(inti=0;i<100;i++){newThread(newStaticThread()).start();}try{Thread.sleep(1000);}catch(Exceptione){e.printStackTrace();}System.out.println(StaticAction.i);}}运行结果则必然是100。加入synchronized关键字的静态方法称为同步静态方法。在访问同步静态方法时,会获取该类的“Class”对象,所以当一个线程进入同步的静态方法中时,线程监视器获取类本身的对象锁,其它线程不能进入这个类的任何静态同步方法。它不像实例方法,因为多个线程可以同时访问不同实例同步实例方法。这个其实就是操作系统中的用信号量实现进程的互斥与同步问题,如果涉及在同一个类中有多个静态方法中处理多线程共享数据的话,那就变成用信号量解决生产者-消费者问题。也就是说,静态方法是一份临界资源,对静态方法的访问属于进入临界区;对静态变量的修改是一份临界资源,对静态变量的修改属于进入临界区。
东风软

2024-09-29 04:13:57

java中 i++ 或者++i这些都不是线程安全的

在java中解决这个问题可以使用synchronized或者AtomicInteger包装类,当然会增加开销.

JDK API 1.6文档中该类的描述和方法如下:

AtomicInteger 可用在应用程序中(如以原子方式增加的计数器),并且不能用于替换 Integer。但是,此类确实扩展了
Number,允许那些处理基于数字类的工具和实用工具进行统一访问。 

int    addAndGet(int delta)
以原子方式将给定值与当前值相加。    

boolean    compareAndSet(int expect,
int update)
如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。    

int    decrementAndGet()
以原子方式将当前值减 1。    

double    doubleValue()
以 double 形式返回指定的数值。    

float    floatValue()
以 float 形式返回指定的数值。    

int    get()
获取当前值。    

int    getAndAdd(int delta)
以原子方式将给定值与当前值相加。    

int    getAndDecrement()
以原子方式将当前值减 1。    

int    getAndIncrement()
以原子方式将当前值加 1。    

int    getAndSet(int newValue)
以原子方式设置为给定值,并返回旧值。    

int    incrementAndGet()
以原子方式将当前值加 1。    

int    intValue()
以 int 形式返回指定的数值。    

void    lazySet(int newValue)
最后设置为给定值。    

long    longValue()
以 long 形式返回指定的数值。    

void    set(int newValue)
设置为给定值。    

String    toString()
返回当前值的字符串表示形式。    

boolean    weakCompareAndSet(int expect,
int update)
如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。    

内谎言太羙。

2024-09-29 00:24:09

++本身不是线程安全的,需要在同步块或同步方法中。