----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
同步函数:
只有当同步代码块和同步函数封装的内容是一样的时候,才可以直接将同步关键字作为修饰符修饰函数即可。
这样函数就具备了同步性。
这就是同步函数。同步的另一种表现形式。
这种表现形式较为简单。
同步函数使用锁是this 。是调用同步函数的对象。
同步函数和同步代码块有什么区别呢?
1,同步函数比同步代码块写法简单。
2,同步函数使用的锁是this。同步代码块使用的锁是任意指定的对象。
建议开发时,使用同步代码块。尤其是需要不同锁时。
静态同步函数使用的锁是什么?
静态随着类的加载而加载的,这时内存中存储的对象至少有一个
就是该类字节码文件对象。
这个对象的表示方式 类名.class 它就表示字节码文件对象。
(重点)
饿汉式。
class Single
{
private static final Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
懒汉式
在被多线程并发访问时,会出现多线程安全问题。
为了解决,加入了同步,虽然安全问题解决了,
但是性能降低了。
有没有办法将安全问题解决的同时,还可以提高性能。
解决改进方法:改成同步代码块。
可以通过双重判断的形式来完成这个过程。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
{
// -->0 -->1
synchronized(Single.class)
{
if(s==null)
// -->0 -->1
s = new Single();
}
}
return s;
}
}
同步的另一个弊端:死锁。
最常见的死锁情况:同步嵌套。
同步中还有同步,两个同步用的不是一个锁。
记住尽量避免同步嵌套的情况。
在0和1之间不断变换
if(x==1){
}else{
}
x=(x+1)%2;
线程间通信:多个线程在处理同一个资源。 但是处理的动作(线程的任务)却不相同。
等待唤醒机制。
涉及到的方法:
wait():等待,将正在执行的线程释放其执行资格和执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait的线程,一次唤醒一个,而且是任意的。
notifyAll():唤醒全部,可以将线程池中的所有wait线程都唤醒,
唤醒的意思就是让线程池中的线程具备执行资格。
这些方法都要使用在同步中才有效。
这些方法在使用时必须标明所属锁,这样才可以明确出这些放操作的到底是哪个锁上的线程。
为什么这些操作线程的方法定义在Object类中?
因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。
能被任意对象调用的方法一定定义在Object类中。
代码演示
synchronized(r)
{
if(r.flag){
try{r.wait();}catch(InterruptedException e){}
}
if(x==0)
{
r.name = "Mike";
r.sex = "man";
}
else
{
r.name = "小红";
r.sex = "女";
}
r.flag = true;
r.notify();
}
synchronized(r)
{
if(!r.flag)
{
try{r.wait();}catch(InterruptedException e){}
}
System.out.println(r.name+"....."+r.sex);
r.flag = false;
r.notify();
}
多生产者多消费者问题。
发生的问题:
生产者生产的商品没有被消费就生产了新的商品。
问题在于两点:
1,本方唤醒了本方。
2,被唤醒的本方没有判断标记。只要将if判断该外while判断。
将if改为while循环判断标记后,出现了死锁。
因为本方唤醒了本方,而被唤醒的本方一判断标记,就继续等待。这样所有的线程都等待了。
必须唤醒对方才行,但是没有直接唤醒对方的动作,所以就使用了notifyAll,唤醒全部。
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------