一,同步锁:锁的是一段代码块
如下图就是一个同步锁
二,方法锁:当同步锁所得是关键字this,并且从头锁到尾,此时就可以把同步锁改为方法锁
如下图所示的同步锁,关键字是this,并且锁了整个方法里的所有内容
就可以把它改成一个方法锁:
三,静态方法锁:锁当前类的字节码对象,从头锁到尾,位于静态方法中。
可以变成:
四,lock锁:这是一个接口(不能被new,要new他的子类)。我们目前学了同步锁,方法锁,静态方法锁,但是我们不知道这个锁是何时加的,何时去掉的! 是系统帮我们处理的。但是lock对象可以人为的加锁和去锁
lock():获取锁,如果锁被暂用则一直等待
unlock():释放锁
tryLock(): 注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true
五,死锁:
如果线程A持有锁L并且想获得锁M,线程B持有锁M并且想获得锁L,那么这两个线程将永远等待下去,这种情况就是最简单的死锁形式。
但是实际环境中的死锁往往比这个复杂的多。可能会有多个线程形成了一个死锁的环路,比如:线程T1持有锁L1并且申请获得锁L2,而线程T2持有锁L2并且申请获得锁L3,而线程T3持有锁L3并且申请获得锁L1,这样导致了一个锁依赖的环路:T1依赖T2的锁L2,T2依赖T3的锁L3,而T3依赖T1的锁L1。从而导致了死锁
一个类可能发生死锁,并不意味着每次都会发生死锁,这只是表示有可能。当死锁出现时,往往是在最糟糕的情况----高负载的情况下。
如图有两个线程,本来线程抢到CPU之后按照橙色路线走,当线程1抢到CPU后,刚打开第一把锁lock1,想打开第二把锁lock2的时候,线程2抢到CPU,同样线程2打开第一把锁lock2,需要打开第二把锁lock的时候。由于线程1还没有释放锁lock1,线程2还没有释放锁2,所以他们会一直处于等待状态,从而形成死锁。
要避免死锁,就要防止嵌套锁。
class AA extends Thread{
Object obj1,obj2;
public AA(Object obj1,Object obj2){
this.obj1=obj1;
this.obj2=obj2;
}
public void run() {
while(true){
synchronized (obj1) {
synchronized (obj2) {
System.out.println("111111111111");
System.out.println("222222222222");
}
}
}
}
}
//****************************************************************
class BB extends Thread{
Object obj1,obj2;
public BB(Object obj1,Object obj2){
this.obj1=obj1;
this.obj2=obj2;
}
public void run() {
while(true){
synchronized (obj2) {
synchronized (obj1) {
System.out.println("AAAAAAAAAAAAA");
System.out.println("BBBBBBBBBBBBB");
}
}
}
}
}
//***************************************************************
public class Test3 {
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
AA a=new AA(o1,o2);
BB b=new BB(o1,o2);
a.start();
b.start();
}
}
这就是个死锁的例子,它的运行结果为:如图,程序还没有停止,但是停了。