黑马程序员——【学习笔记】多线程——多线程的锁


------- android培训 java培训 、期待与您交流!----------


多线程的锁即用于synchronized()语句判断是否可以让当前线程进入同步代码的对象。注意:锁的本体是一个对象。


1 锁有三种作用形式:

1.1 同步代码块

synchronized(Object obj){//需要被同步的代码} 锁是Object obj


如下例子:演示2个线程倒数100到1;


1.2 同步函数

即在函数上直接标注synchronized:public synchronized void show(){//需要被同步的代码}; 锁是this

如下:

class Day13{
	public static void main(String[] args){
		Demo d = new Demo();
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		t1.start();
		t2.start();
	}
}
class Demo implements Runnable{
	private int x = 100;
	public void run(){
		while (true){
			show();
		}
	}
	synchronized void show(){
		if (x>0){
			System.out.println(Thread.currentThread().getName()+"..."+x);
			x--;
		}
	}
}

因为非静态的方法必然要被类的对象调用,所以调用该方法的类对象this是必然存在的。非静态方法的synchronized默认锁就是用this


1.3 静态的同步函数

在静态函数上使用synchronized:static synchronized void show(){//需要被同步的代码}; 锁是this.getClass()的返回值(返回一个类),即类文件本身。

只要上述程序稍加更改即可得到静态函数的同步。

class Day13{
	public static void main(String[] args){
		Demo d = new Demo();
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		t1.start();
		t2.start();
	}
}
class Demo implements Runnable{
	private static int x = 100; //被静态函数调用,
	public void run(){
		while (true){
			show();
		}
	}
	static synchronized void show(){ //静态
		if (x>0){
			System.out.println(Thread.currentThread().getName()+"..."+x);
			x--;
		}
	}
}
对于静态方法,它不依赖于具体的对象,而是类本身,而一个运行的类必然存在类文件,即Xxx.class文件。它就是静态方法同步中的锁。


2 锁的效率提高。

同步代码被同步之后,凡是试图执行这些代码的线程都要先判断能否获取锁,也就是在synchronized里判断一次。

如果很多线程同时运行的话,频繁判断同步就会降低程序的效率。这时最好有一定的优化。

比如单例设计模式的懒汉式:

class Single{
	private static Single s  = null;
	private Single (){}
	public static synchronized Single getInstance(){
			if (s == null){
				s = new Single();
		}return s;
	}
}

懒汉式的单例设计模式在多线程运用时可以直接用静态的同步解决,但是这样每次线程到来都会判断一次。

要避免这种情况,需要:

class Single{
	private static Single s  = null;
	private Single (){}
	public static  Single getInstance(){
			if (s == null){
				synchronized(Single.class){
					if(s == null)
						s = new Single();
					}
			}return s;
	}
}
这样,任何一个线程在执行到第一个if判断语句时,如果Single对象已经创建,则直接获取即可,不用判断是否能够获取锁,相对于上面使用同步函数的方法就升了效率。如果当前线程发现Single对象尚未创建,则再来判断是否能够获取锁。

如果判断得到Single对象尚未创建,再进入第二个if判断是否需要创建对象。

为什么明知道第一个if判断出对象尚未创建了,还需要第二个?它的意义是啥?

————这是因为有可能当此线程获取对象未创建后,获取锁之前,线程代码里正有线程正在创建Single对象,此时该线程必须被同步挡在外面,等里面的创建完了,第二个if就能告诉它前面的线程已经创建完成。它可以离开了~~这样该线程只能离开同步代码,直接获取Single对象。


3 死锁

死锁简单的说,就是两个线程各自携带这自己的锁(肯定是不同的锁),但是下一步需要获取对方的锁才能执行。但是因为线程未执行完同各自的步代码之前,是不会释放手头的锁的。这样双方都只能停止下来,称为死锁。

......
public void run(){
	while(ture){
		synchronized (obj){
			demo();
		}
	}
}
synchronized void demo(){
	synchronized (obj){
	}
	}
}
......
如上面的情形,当run和demo被同时执行的之后,因为run需要获取demo的锁(this),而demo需要获取run的锁(obj),双方未结束本次的语句之前都不会释放锁,很快他们就会产生死锁。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值