java 大道至简--多线程(11)

java 大道至简--多线程(11)

内容目录

使用Lock来代替synchronized

正文:

上一篇中我们讲到了,死锁问题以及解决死锁问题常见的一些解决方案,现在我们简单的总结一下,synchronized的一些特点

synchronized:

1、简单,不要手动释放锁,jvm会自动帮我们释放锁资源

2、synchronized同步块中的锁的使用

  package test3;
public class T implements Runnable{
static Object aa = "1aa";
static int i = 10;
@Override
public void run() {
while(i > 0) {
synchronized(this) {
System.out.println("i="+i);
i--;
   }
try {
Thread.sleep(1 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
T t = new T();
Thread thread1 = new Thread(t,"1");
Thread thread2 = new Thread(t,"2");
thread1.start();
thread2.start();
}

}

此时我们同步块的锁的当前这个类本身,我们可以得出一个规律:

当我们用多个Thread对象的时候,锁是当前线程本身

扫描二维码关注公众号,回复: 1708646 查看本文章

当我们用一个Thread对象的时候则锁是一个类变量

不是很理解的可以把我们前一篇的实例来过来,做一个对比,然后好好揣摩一下

3、synchronized使用不灵活,拓展性不好,所以我们使用lock来替代synchronized

4、必须要有一把锁标识,即类变量或者this即线程本身

5、没有超时机制,即如果发生死锁问题,系统很难自动解决


为了解决锁的拓展性问题,我们下面介绍锁的另一种常用方法,即java.util.concurrent.locks包下面的lock接口

Lock接口的基本介绍:

1、Lock是一个接口,它用来提供比synchronized更加广泛的锁定操作

2、需要手动释放资源,并且有超时机制,可以有效避免死锁问题

3、可以获取Condition对象以执行线程的挂起操作

介绍:

   public Interface Lock 中的函数包括

 public void lock();  --> 获取锁

public void lockInterruptibly();  --> 如果线程没有中断则获取锁

public booleantryLock()/tryLock(long time , TimeUnit nano); --> 只有在调用的时候才获取锁/在指定的毫秒加上纳诺秒获取锁

public Condition newCondition(); --> 获取线程状态的对象

public void unLock(); --> 释放锁

Lock接口的实现类

ReentrantLock , ReentrantReadWriteLock.writeLock , ReentrantReadWriteLock.readLock

下面我们就ReentrantLock的使用做一个简单的介绍

package test3;


import java.util.concurrent.locks.ReentrantLock;


public class T {
   public static void main(String args[]) {
  T1 t1 = new T1();
  T2 t2 = new T2("t1" , t1);
  T2 t3 = new T2("t2" , t1);
  t2.start();
  t3.start();
   }
}


class T1 {
private final ReentrantLock lock = new ReentrantLock();

void test(){
try {
lock.lockInterruptibly();
System.out.println(lock.isLocked());
System.out.println(Thread.currentThread().getName());
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}


class T2 extends Thread{
T1 t1 ;
T2(String name , T1 t1){
super(name);
this.t1 = t1;
}
@Override
public void run() {
t1.test();
}
}

结果:

true
t1
true

t2

分析:

我们可以看出t1和t2是同步的,即等到t1资源释放以后t2才运行

ReentrantLock还有一些常用的函数,以此来帮我们更好的判断当前锁的使用是否合理

public int getHoldCount();  当前线程保持此锁的次数

public int getQueueLength(); 查看后面有多少线程在等待

public boolean hasQueueThread()/hasQueueThread(Thread thread); 查看是否还有线程等待获取此锁

public boolean isHeldByCurrentThread(); 查看当前线程是否获得此锁

通过上面的函数可以非常灵活的知道我们当前锁的使用情况








猜你喜欢

转载自blog.csdn.net/xianghan_qq/article/details/80759370
今日推荐