首页新闻找找看学习计划

ReentrantLock和synchronized

0
悬赏园豆:20 [已解决问题] 解决于 2016-12-14 08:48

网上看了很多ReentrantLock和synchronized的区别,但是我想问的一点是,方法分别被两个锁锁上时,线程需要获取的锁有什么区别?本人测试方法A和方法B,一个用ReentrantLock加锁一个用synchronized加锁,还会出现线程同步问题。

让我发会呆的主页 让我发会呆 | 老鸟四级 | 园豆:2636
提问于:2016-12-13 10:46
< >
分享
最佳答案
0

贴代码吧~~

收获园豆:20
Daniel Cai | 专家六级 |园豆:10374 | 2016-12-13 11:51

public static void main(String[] args) throws InterruptedException {
ThreadDemo demo = new ThreadDemo();
new Thread(new Thread0(demo)).start();
new Thread(new Thread1(demo)).start();
System.out.println("main结束");
}

public class Thread0 implements Runnable{

private ThreadDemo demo;

public Thread0(ThreadDemo demo){
this.demo = demo;
}

@Override
public void run() {
demo.A();
System.out.println("0结束");
}

}

 

public class Thread1 implements Runnable{

private ThreadDemo demo;

public Thread1(ThreadDemo demo){
this.demo = demo;
}

@Override
public void run() {
demo.B();
System.out.println("1结束");
}
}

 

public class ThreadDemo {

private Lock lock = new ReentrantLock();

public void A(){
try {
lock.lock();
for(int i=0; i<10; i++){
System.out.println("A"+Thread.currentThread().getName()+":"+i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
lock.unlock();
}
}

public synchronized void B(){
// lock.lock();
for(int i=0; i<10; i++){
System.out.println("B"+Thread.currentThread().getName()+":"+i);
}
// lock.unlock();
}
}

 

结果:

AThread-0:0
main结束
BThread-1:0
BThread-1:1
BThread-1:2
BThread-1:3
BThread-1:4
BThread-1:5
BThread-1:6
BThread-1:7
BThread-1:8
BThread-1:9
1结束
AThread-0:1
AThread-0:2
AThread-0:3
AThread-0:4
AThread-0:5
AThread-0:6
AThread-0:7
AThread-0:8
AThread-0:9
0结束

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 11:56

@让我发会呆: 你那个sleep。。。。。

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 12:20

@Daniel Cai: sleep并不会释放锁,只是让为了让同步问题展现出来,否则10条数据很难出现异步。

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 13:05

@让我发会呆: 多线程和异步是两码事,我是说你那个sleep导致b执行完了a还在sleep。

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 13:17

@Daniel Cai: 这个就是我要问的问题,如果把A方法改为synchronized,获取把B方法改为用lock.lock()锁住,即使你再怎么sleep,依然会其中一个线程执行完,另一个线程才会执行

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 13:21

@让我发会呆: 你怎么还没明白?你那一sleep,100ms这种循环可以跑上万次,你这sleep一下肯定会导致最后输出变成那样。

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 13:41

@Daniel Cai: 把B方法改为

public void B(){
lock.lock();
for(int i=0; i<10; i++){
System.out.println("B"+Thread.currentThread().getName()+":"+i);
}
lock.unlock();
}

A不变

运行结果:

AThread-0:0
main结束
AThread-0:1
AThread-0:2
AThread-0:3
AThread-0:4
AThread-0:5
AThread-0:6
AThread-0:7
AThread-0:8
AThread-0:9
0结束
BThread-1:0
BThread-1:1
BThread-1:2
BThread-1:3
BThread-1:4
BThread-1:5
BThread-1:6
BThread-1:7
BThread-1:8
BThread-1:9
1结束

可以看出两线程是串行的,A方法再怎么sleep,也不会改变运行结果啊。

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 13:45

@让我发会呆: 你放大迭代次数到1k你再看。

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 13:57

@Daniel Cai: 哇,园龄8年老司机啊,崇拜!

不过现在只有两个线程,其中一个进入A时,获取锁,无论它执行多慢,sleep多久,其他的线程肯定没办法再次获取该锁的,只有其中一个线程执行完,另一个才会去执行,这应该是没问题的吧,现在是两种锁混合使用,没有起到锁该有的作用。这两种锁应该是有一些比较深层的区别,我也只是好奇问一问,看看有没有遇到类似问题的圆友。

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 14:20

@让我发会呆: 前面说的是对的。

后面不对,10次迭代周期太短,很难看到区别,你要么就两个方法内都sleep 10 ms看下结果。

从本质上说synchronized锁实例,ReentrantLock通过cas来模拟所谓“锁”的过程。

而且后者可以有着更加精细的控制,比如从lock派生的ReadWriteLock等。

 

 

PS:你的代码没有任何所谓的同步问题

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 14:37

@Daniel Cai: 第一种结果的加锁方式,即使不加任何sleep代码,当迭代次数达到一万时,会出现Thread0和Thread1交替执行,这难道不是同步问题吗?

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 14:53

@让我发会呆:你这里连竞争都没有,哪来的同步问题?

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 14:55

@Daniel Cai: 说的我有点懵逼了,怎么就没有竞争了,两个线程都去访问ThreadDemo的方法,这不是竞争吗?而且我加锁不就是为了解决因为竞争(并发)可能导致数据错乱的问题啊。

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 15:32

@让我发会呆: 这两个线程虽然都是访问同一个对象,但它们之间没任何关系啊,

一个线程访问a访问,一个线程访问b方法,这两个方法间又没有共享变量,你这里就算把这些同步措施全部拿掉结果也不会有任何变化。

你可以把i提升为对象字段,然后两个方法分别for(;i++;i<1000),不使用任何同步手段就会出现问题

for(;i++;i<100){

//your work here

Thread.sleep(1);

}

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 15:46

@让我发会呆: ps下,如果使用我上面说的方法如果需要保证数据正确性,必须使用同种同步方式,如果还是按照你的代码两种混在一起还是有问题。

关于线程安全性,你只要保证在任意时刻如果多个线程对同一对象做了变化,那么你就要注意了。

Daniel Cai | 园豆:10374 (专家六级) | 2016-12-13 15:49

@Daniel Cai: 我只是代码里没有对同一数据进行改变,模拟一下而已,因为如果出现线程交替运行,我就认为会出现线程并发的问题啦

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 18:04

@Daniel Cai: 是的,这两个锁一起用并没什么用,以后遇到再去发现原因吧,谢谢你了

让我发会呆 | 园豆:2636 (老鸟四级) | 2016-12-13 18:05
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册