黑马程序员—多线程安全问题(锁)


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


一、多线程安全问题解析

多线程安全问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,

另一个线程参与进来执行。导致共享数据的错误。


二、解决方法

解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。

java对于多线程的安全问题提供了专业的解决方式。


这个解决方式就是同步代码块。
synchronized(对象)
{
需要被同步的代码

}


对象如同锁。只有锁的线程可以在同步中执行。

没有持有锁的线程即使获取了cpu的执行权,也进不去。 

如同商场中的试衣间,一个人出去,另外一个进来。不过也有例外就是优衣库的试衣间,这个不算。


同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
3,必须保证同步中只能有一个线程在运行。

如果加了同步,还出现错误。说明没有达到前提。

好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源。


同步代码块例:


class Ticket implements Runnable//extends Thread
{

private int tick = 100; 
Object obj = new Object();//这里可以是任意对象。
public void run()
{
while(true) 
{
 synchronized(obj)
{
if (tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}//这里加try是因为sleep方法默认的抛出了错误。所以必须处理
System.out.println(Thread.currentThread().getName()+"...sale:"+tick--);

 }
}  
}
}


class TicketDemo2 
{
public static void main(String[] args) 
{
Ticket t = new Ticket(); 


Thread t1= new Thread(t);
Thread t2= new Thread(t);
Thread t3= new Thread(t);
Thread t4= new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}

}


如何找同步中的问题:

1,明确哪些代码是多线程运行代码

2,明确共享数据。

3,明确多线程运行代码中哪些语句是操作共享数据的。

另外synchronized可作为修饰符修饰函数使函数具备相同功能。publi synchronized .........

并且同步函数的锁是this.

证明同步函数锁是this:

通过该程序进行验证。使用两个线程来买票。一个线程在同步代码块中。
一个线程在同步函数中。都在执行买票动作。




class Ticket implements Runnable
{
private int tick = 100;
Object obj = new Object();//这里new对象是因为下面的同步锁要传入一个对象,任意对象都可以
boolean flag = true;//但是如果传别的对象,还需要在建一个类。
//public synchronized void run()//不可以这么做。因为其中有些代码不需要同步。
/*public void run()
{
while (true)
{
show(); //相当于this.show();
}
}*/
public void run()//为了看两个同步是否为同一个锁。一个线程执行同步代码块。一个线程执行同步函数。
{
if (flag)
{
 while(true)
 {
synchronized(this) //证明了同步函数的锁为this,因为如果这里用obj锁的话,会出现错误。只有多进程使用一个锁的时候结果才是正确的。
{
if (tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....sale:"+tick--);
}
}
}
}
else
while(true)
show();
}
public synchronized void show() //锁为this
{
if (tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....show...:"+tick--);
}
}
}


class  ThisLockDemo
{
public static void main(String[] args) 
{
Ticket t = new Ticket ();


Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}//如果这里t1线程不Sleep那么主线程就会把后面的都执行。
t.flag = false;
t2.start();

}

}


如果同步函数时静态的话,那么它的锁是Class.

因为静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
类名.Class 该对象的类型是Class


其实懒汉式的单例模式很好的说明了同步的作用

class Single

{

private  Static Single s = null;

private Single(){};

public static Single getIntance()

{

if(s==null)  //这样做能提高效率,不用每个都判断锁。

{

synchronized(Single.class)  //因为是静态同步方法锁是class

{

if(s==null)

s = new Single;

}

}

return s;

}


}

三、死锁问题

死锁:同步中嵌套同步,而锁却不同就会造成死锁。程序进入等待

class Ticket implements Runnable
{
private int tick = 100;
Object obj = new Object();
boolean flag = true;
public void run()
{
if (flag)
{
 while(true)
 {
synchronized(obj)
{
show();
}
}
}
else 
while(true) 
show();
}
public synchronized void show() //这里锁是this与另外的同步代码块锁不同,造成死锁。
{
synchronized(obj)
{
if (tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....show...:"+tick--);
}
}
}
}


class  DeadLockDemo
{
public static void main(String[] args) 
{
Ticket t = new Ticket ();


Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.flag = false;
t2.start();


}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值