多线程同享数据(多个线程共同拜访相同的数据),需求进行数据同步,保证同一数据、同一时间只能被一个线程拜访。
运用同步是为了避免多个线程同一时间对同一数据进行读写,假如对同一数据数据都只进行读操作、不进行修正,则不用运用同步。
以售票为例不运用同步
publicclassSaleTicketThreadextendsThread{privatestaticintticket=100;//票数,static@Overridepublicvoidrun(){while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”个座位”);
ticket–;
}
}
}
publicclassSaleTicket{publicstaticvoidmain(String[]args){
SaleTicketThreadthread1=newSaleTicketThread();
thread1.start();
SaleTicketThreadthread2=newSaleTicketThread();
thread2.start();
SaleTicketThreadthread3=newSaleTicketThread();
thread3.start();
}
}
启动三个线程来售票,这3个线程都要拜访同一个数据SaleTicketThread.ticket剩下票数
很简单出问题
三种常见的同步办法
同步办法默认用当时目标(this)或许当时类的class目标作为锁,会给整个办法都加锁
同步代码块能够选择以什么作为锁,能够只同步会发生同步问题的部分代码而不是整个办法,比同步办法愈加细粒度
ReentrantLock以ReentrantLock目标作为锁,能够只给部分代码加锁,比同步办法愈加细粒度
1、同步办法
publicclassSaleTicketThreadextendsThread{privatestaticintticket=100;//票数,staticprotectedstaticsynchronizedvoidsaleTicket(){//用synchronized润饰办法while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”个座位”);
ticket–;
}
}
@Overridepublicvoidrun(){
saleTicket();
}
}
假如办法没有运用static润饰,是实例办法,默认以this(当时目标)作为锁,假如此线程类有多个实例(多条线程),这些线程运用的锁不是同一个目标,起不到同步的效果。
假如办法是静态办法,默认以当时类的class目标作为锁,假如此线程类有多个实例(多条线程),这些线程运用的锁是同一个目标,实现了同步,显然应该运用static。
同步办法有一个很大的问题:只效果于当时线程类,比如查询、售票2个线程类都要运用剩下票数这个同享数据,都运用同步办法,锁目标不同,这2个线程类之间并没有同步。
所以同步办法一般用于此同享数据只效果于一个线程类的多个实例。
锁的规模是固定(整个办法),不能修正,不灵活;运用状况还有约束,有点鸡肋。
相比之下,同步代码块、ReentrantLock的运用不受约束,强大多了。
2、同步代码块
publicclassSaleTicketThreadextendsThread{privatestaticIntegerticket=100;//票数,static@Overridepublicvoidrun(){synchronized(ticket){//锁要是Object类型while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”个座位”);
ticket–;
}}}
}
同步代码块能够自己决议要运用的锁目标,能够直接把同享数据作为锁,也能够新建一个Object目标作为锁。
要注意2点:
1、锁要是Object类型,int、float、char等根本类型没有承继Object,不能作为锁,要运用对应的包装类型。String承继了Object,能够作为锁。
2、拜访这一同享数据的线程,运用的锁目标要相同(目标地址要相同)。
3、ReentrantLock
publicclassSaleTicketThreadextendsThread{privatestaticIntegerticket=100;//票数,staticprivatefinalstaticReentrantLocklock=newReentrantLock();//锁目标,finalstatic润饰,@Overridepublicvoidrun(){lock.lock();//加锁while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”个座位”);
ticket–;
}lock.unlock();//开释锁}
}
以ReentrantLock目标作为锁,注意一切要运用此同享数据的线程运用的应该是同一个ReentrantLock目标(要是同一个锁目标)。
其实和同步代码块差不多,lock()标志同步代码块开始,unlock()标志同步代码块完毕。
可能发生反常的状况:
publicclassXxxThreadextendsThread{privatefinalstaticReentrantLocklock=newReentrantLock();//锁目标,finalstatic润饰@Overridepublicvoidrun(){//…lock.lock();//加锁try{//……//放在try中}catch(){//…..}finally{
lock.unlock();//在finally中开释锁,避免发生反常后锁没有开释,其它线程一直等候}//…..}
}
说明
能够把同享数据、锁能够放在某个线程中作为静态变量,
假如要在不同的线程类中运用,比如在查询、售票2个线程类中都要运用剩下票数这个成员变量,那就声明为publicstatic,暴露出来;
假如只在一个线程类中运用(此线程类的多个实例同享此数据),设置成privatestatic即可。
也能够把同享数据、锁放在父线程(开启它们的线程)中,在线程类的结构函数中传入同享数据、锁目标。
总之,要一切拜访这个同享数据的线程都能够拜访到同享数据、锁。
1、IT大王遵守相关法律法规,由于本站资源全部来源于网络程序/投稿,故资源量太大无法一一准确核实资源侵权的真实性;
2、出于传递信息之目的,故IT大王可能会误刊发损害或影响您的合法权益,请您积极与我们联系处理(所有内容不代表本站观点与立场);
3、因时间、精力有限,我们无法一一核实每一条消息的真实性,但我们会在发布之前尽最大努力来核实这些信息;
4、无论出于何种目的要求本站删除内容,您均需要提供根据国家版权局发布的示范格式
《要求删除或断开链接侵权网络内容的通知》:https://itdw.cn/ziliao/sfgs.pdf,
国家知识产权局《要求删除或断开链接侵权网络内容的通知》填写说明: http://www.ncac.gov.cn/chinacopyright/contents/12227/342400.shtml
未按照国家知识产权局格式通知一律不予处理;请按照此通知格式填写发至本站的邮箱 wl6@163.com