线程Lock
我们之前学习了synchronized,今天来介绍一下lock。lock与synchronized一样都是为了多线程在竞争公共资源时,能不发生冲突,就是一个线程获取了锁,就去执行代码块,其它线程只能等待第一个线程执行完同步代码块,才能有机会获取到synchronized锁对象。
lock与synchronized最大的区别是,lock锁的释放需要程序员手动调用unlock,一般放在要同步的代码的最后调用unlock,或者try..catch..finally中的finally里调用unlock。当然,从lock释放锁的灵活性上来说,lock的性能更高些,因为synchronized必须等待代码块整个执行完毕才能自动释放锁,而unlock可由程序员手动释放,随时释放,只要不影响多线程同步。
synchronized与lock的示例代码如下:
-
package cn.itcast.heima2;
-
-
import java.util.concurrent.locks.Lock;
-
import java.util.concurrent.locks.ReentrantLock;
-
-
-
public class LockTest {
-
-
/**
-
* @param args
-
*/
-
public static void main(String[] args) {
-
new LockTest().init();
-
}
-
-
private void init(){
-
final Outputer outputer = new Outputer();
-
new Thread(new Runnable(){
-
@Override
-
public void run() {
-
while(true){
-
try {
-
Thread.sleep(10);
-
} catch (InterruptedException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
outputer.output("gaoxiaowei");
-
}
-
-
}
-
}).start();
-
-
new Thread(new Runnable(){
-
@Override
-
public void run() {
-
while(true){
-
try {
-
Thread.sleep(10);
-
} catch (InterruptedException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
outputer.output("liudehua");
-
}
-
-
}
-
}).start();
-
-
}
-
-
static class Outputer{
-
Lock lock = new ReentrantLock();
-
public void output(String name){
-
int len = name.length();
-
lock.lock();
-
try{
-
for(int i=0;i<len;i++){
-
System.out.print(name.charAt(i));
-
}
-
System.out.println();
-
}finally{
-
lock.unlock();
-
}
-
}
-
-
public synchronized void output2(String name){
-
int len = name.length();
-
for(int i=0;i<len;i++){
-
System.out.print(name.charAt(i));
-
}
-
System.out.println();
-
}
-
-
public static synchronized void output3(String name){
-
int len = name.length();
-
for(int i=0;i<len;i++){
-
System.out.print(name.charAt(i));
-
}
-
System.out.println();
-
}
-
}
-
}
其中output函数使用了lock,于是两个thread不断输出字符串“gaoxiaowei”,“liudehua”,就不会乱,不会出现类似于这样的输出:"gaoxliudehuaiaowei"
其中output2函数使用了synchronized ,它也可以达到多线程同步的效果。
值得注意的是如果 生成两个Outputer对象就不行了,例如再创建一个Outputer对象, final Outputer outputer2 = new Outputer(); 然后让输出liudehua的线程(第2个new Thread) 使用outputer2.output照样会乱,例如类似于这样的输出:"gaoxliudehuaiaowei"。这是因为synchronized或lock,创建的锁对象就是output对象。多线程调用同一Outputer 对象的output函数可以达到同效果,但是当一个线程使用output对象,第二个线程使用output2对象,那么这两个线程在调用output.output()函数与output2.output()函数时,是不会同步的,因为它们分别持有的锁是output.this 与 output2.this,是两把不同的锁,各自玩各自的,互相不受影响,都无法锁住对方。
其中其中output3函数使用了synchronized, output3注意了,是一个静态函数,synchronized关键字对应的锁对象是 Output.class类的字节码,它能锁住所有类对象,这个时候即使创建了inal Outputer outputer2 = new Outputer(); 让线程1调用 outputer.output3(),线程2调用output2.output3(), 是不会出现错乱的,因为outputer与output2都属于Output类型,synchronized关键字对应的锁对象是 Output.class类的字节码,它们在执行output3()函数时,用的是同一把锁:Output.class。因此最终还是可以达到多个线程同步输出字符串到屏幕设备的。
但是,无论是synchronized,还是我们上述讲的lock, 性能都很差,因为它们的锁有些盲目,比如当2个线程都是读数据,并没有去写数据,所以不会出现多线程读取多乱问题。这个时候synchronized和lock就有点死板了,当第1个线程读取变量值(或数据)的时候,线程2也想读,但是必须得等线程1把锁释放了才行,即使线程2不是来捣乱的。
要改善读-读性能问题,需要使用ReentrantReadWriteLock(读写锁)来分别创建读锁 和 写锁。读锁就能解决上述问题,让读--读自由。
文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/116096384
- 点赞
- 收藏
- 关注作者
评论(0)