今天讲的是线程的另一个重要内容,就是同步,
首先需要同步的原因:线程间共享代码和数据可以节省系统开销,提高程序运行效率,但同时也导致了数据的“访问冲突”问题,如何实现线程间的有机交互、并确保共享资源在某些关键时段只能被一个线程访问,即所谓的“线程同步”(Synchronization)就变得至关重要。
多个线程间共享的数据称为临界资源(CriticalResource),由于是线程调度器负责线程的调度,程序员无法精确控制多线程的交替顺序。因此,多线程对临界资源的访问有时会导致数据的不一致行。
互斥锁
每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。
关键字synchronized用来与对象的互斥锁联系
当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象
同步的两种表现形式:
1.同步代码块
synchronized(对象){
需要同步的代码
}
2.同步函数:使用的锁是this
publicsynchronizedvoidshow(){
}
同步的作用:避免线程的安全隐患
所以为了避免线程出现堵塞或者冲突,同步的作用还是很大的,就例如底下的买票系统,就必须用到同步
。
packagecom.csdn;
publicclassTestMulThread{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
Ticketst=newTickets();
TicketThreadt1=newTicketThread(t,"小王");
TicketThreadt2=newTicketThread(t,"小张");
}
}
classTickets{
publicintticket;
publicTickets(){
ticket=10;
}
publicsynchronizedvoidaction(Stringname){//同步函数,防止出现重复;
System.out.println(name+"买了"+ticket+"票");
ticket--;
}
}
classTicketThreadextendsThreadimplementsRunnable{
Ticketst;
Stringname;
publicTicketThread(Ticketst,Stringname){
this.t=t;
this.name=name;
start();
}
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
for(inti=0;i<5;i++){
t.action(name);
}
}
}
做到这里,想起了单例类也有这样的问题,单例类的懒汉式会出现同样的问题所以也会用到同步;
懒汉式
classSingle{
privatestaticSingles=null;
privateSingle(){}
publicstaticSinglegetInstance(){
if(s==null)
synchronized(Singel。class){
if(s==null)
s=newSingle();
}
returns;
}
classSingle{
privatestaticSingles=null;
privateSingle(){}
publicstaticsynchronizedSinglegetInstance(){
if(s==null)
s=newSingle();
returns;
}
Single。getInstance();
饿汉式
classSingle{
privatestaticSingles=newSingle();
privateSingle(){}
publicstaticSinglegetInstance(){
returns;
}