线程:共享资源(二)

[size=medium]synchronized关键字被添加到实例方法的前面时,[color=blue]只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法[/color][/size]([size=medium][b]对象级的锁[/b][/size])
SomeClass中的同步方法:
public synchronized (static) void dosomething() {
while (true) {
System.out.println(Thread.currentThread().getName()
+ ":dosomething");
}

}
public synchronized (static) void doit() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":doit");
}
}
1、放在实例方法前面(即那些非具体方法)
while(true)时两个线程能同时进到方法里边,分别调用dosomething方法交替的进行着。但当我们设置synchronized关键字在dosomething方法前面时,这时候就只有一个线程先调用dosomething方法了,具体是哪个线程先抢到这把锁,即这个对象的锁,抢到了他就能访问有这把锁控制的那些方法。因为这dosomething是个死循环,那么另一个线程永远都得不到机会执行这个方法。
任何一个对象都有一把锁,可以想象创建一个对象后就已经有锁了。现在再添加一个doit方法,但没有在该方法前面设置synchronized关键字,因此这是两个线程都能访问到这个方法,因为这个方法是Someclass这个对象的一个方法,而Client中的两个线程,都使用到了Someclass这个对象的共享资源,所以也是交替的执行着doit方法。但如果在doit方法前面设置为同步的话即synchronized,那么根据同步的特性,这个方法对于这个对象来说是同步的,因为前面的dosomething方法是同步的,所以呢doit必须等到前面的dosomething方法执行完才会执行它的操作,显然它没有机会执行了。务必要注意上面两个线程调用的是同一个对象,如果在MyThread中new SomeClass的话,那么这是两个不同的sc对象了。因此dosomething和doit方法都能调用到,是针对的是同一对象而言的
可以把sc想成是一个房间,房间里边的有一堆synchronized定义的方法,房外面有一堆人在等,谁抢到了这把锁就可以进去,其他等待中直到进去的人出来后,某人才能拿到这把锁进去执行里边的方法,因此synchronized是一个四周围起来的围墙,只有拿到这把锁才能进去,相当于一个临界区。如果不是synchronize修饰的方法则没有这个围墙,任何人任何时刻想进去就进去执行操作。
2、放到静态方法前面的时候,只有一个线程可以调用这个类的静态方法(类级别的锁)
把上面的两个方法改成static,那么锁就是加在这个类上了,如果把其中一个static去掉的话,那么这时候就有两把锁,分别是指这个对象和这个类的锁,由于锁的范围不同,因此都能同时访问
public void doit() {
for (int i = 0; i < 23; i++) {
System.out.println("for循环"+i);
}
synchronized (this) {
while (true) {
System.out.println(Thread.currentThread().getName() + ":doit");
}
}

}
3、synchronized同步代码块
有时候,如果将synchronized关键字定义在方法前面的话,显得控制的粒度太粗糙了,可以对方法内部涉及到共享资源部分的访问放到同步块中即可。
synchronized (this或者其他对象或者类级别锁) {},关键是要弄清楚锁的范围,在同一个锁范围内是不允许有两个同步块同时执行的,一个synchronized必须等另一个synchronized方法执行完后才能进行。
可以想象这是不同的临界区房间,定义了不同的锁,同步代码块中必须指定一个对象,这个对象的锁被用来控制对这段代码的访问,只有线程获得了这个对象的锁之后,才可以访问,上面中this可以SomeClass类或者其他自己定义的对象,他们分别是不同的锁

线程:互斥与协作

Synchronized控制的资源,就像四周围墙围起来一样,外边的线程想进来拿到这把锁,进到这个房间,操作里面的一些方法,只要有人还持有这把锁没有释放,其他线程只能等待。
通过wait和notify方法这种监视器模型——互斥与协作,对这把锁进行控制,想要取得这把锁就必须等待取得这把锁,操作锁里边的资源,用完了要通知别的线程,从而保证线程的工作,最大限度地利用线程。
CountDownLatch:cd线程计数器
cd.await()等待所有线程执行完毕
cd.countDown所有的线程结束

[b]wait和sleep的区别[/b]
wait是Object类中的方法,而sleep是Thread中的方法
wait只能在synchronized里面用,而且要注意synchronized锁定的是哪个对象,你只能调用那个对象的wait方法
wait会释放锁,而sleep不会

volatile:为了提高线程性能所产生的一个小BUG,在多线程中JVM可能会优化这个值,每个线程都会保留它自己的副本,其他人可能压根儿看不到。而volatile就是避免线程创建本地副本的属性,避免线程本地优化性能,从而直接在主存中修改,一改大家都能看到。这就是线程的可见性,但是他不能避免线程的有序性,因为每个人都是直接操作主存的,大家都能看到这个值的变化,谁都可以在任何时刻修改它。而synchronized则控制了这种有序性,保证大家都能看到的同时,而你必须等里面的那个人把锁释放掉才有机会去操作它,这就保证了线程的有序性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值