一、线程的同步
在多线程程序中,它们多个线程之间是共享一块内存的。
当某个线程正在读取该内存块的信息时,并在修改内存信息的同时,并在此发生意外,如:阻塞,如果有别的线程也进来访问这块内存,并且也要修改该内存块的信息,这是就会发生意想不到的错误。
比如:你有一个银行账户,账户里面有2000块钱。
一天,你拿着银行本子去银行取钱,打算取1500,然后银行的工作人员就会通过电脑程序检查你的账户中是否有超过1500的钱,查询之后,证明你的账户有超过1500,可以取款,然后响应取款的程序!当然,你取款程序执行完之后,才会从你的账户减去1500,然而就在执行取款程序的同时,也就是还没从你的账户里减去1500;巧的是,这时你的老妈/老爸拿着你的银行卡也在l另一处的取款机上取钱,取款机同时也会去检查你的账户里的钱有没有超过1500,这时当然超过1500,然后你老妈取钱成功啦,你也取钱成功,然后你们家取了3000块,卡里还剩500,这种好事多好啊。
。。。。。
当然,这种事情是不会发生的,哈哈!!
要解决上面这个问题,我们就得了解程序的原子性这个概念。
程序的原子性:
也就是说保证一个程序或者某个代码块完整执行的性质,在这个过程当中,别的线程如果想执行该代码块时是没有权限的。
还有如果在执行过程,突然中断该程序,程序的内存信息是不会修改的。
synchronzied 关键字:
对象锁。有了对象锁,就保证了在一个线程执行某个代码块的时候,别的线程就不访问到该代码块了,就避免了像上面那样造成数据混乱了。
如下模仿一个多窗口售票的程序:
没有关键字synchronize之前:
1 package com.thread.Synchronized; 2 3 /** 4 * 线程同步 5 * --》synchronized关键字 6 * 7 * 模拟一个多窗口售票的例子 8 * 9 * @author hunjun 10 */ 11 public class TestSync implements Runnable{ 12 private static int ticketNum = 200; 13 14 public static void main(String[] args) { 15 TestSync ts1 = new TestSync(); 16 TestSync ts2 = new TestSync(); 17 TestSync ts3 = new TestSync(); 18 19 Thread t1 = new Thread(ts1,"窗口一"); 20 Thread t2 = new Thread(ts2,"窗口二"); 21 Thread t3 = new Thread(ts3,"窗口三"); 22 23 t1.start(); 24 t2.start(); 25 t3.start(); 26 } 27 28 @Override 29 public void run() { 30 // TODO Auto-generated method stub 31 try { 32 while(ticketNum > 0){ 33 Thread.sleep(2000); 34 TestSync.saleTicket(); 35 } 36 } catch (InterruptedException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } 40 } 41 42 public static void saleTicket(){ 43 if(ticketNum > 0){ 44 //开始售票 45 System.out.println(Thread.currentThread().getName()+"售出第 "+ticketNum+" 张票。。"); 46 ticketNum --; 47 } 48 } 49 50 }
结果;
窗口一售出第 200 张票。。
窗口二售出第 200 张票。。
窗口三售出第 200 张票。。
窗口一售出第 197 张票。。
窗口三售出第 197 张票。。
窗口二售出第 197 张票。。
数据很混乱。。。因为在当前线程sleep的时候别先进来来,改变数据,就会出现混乱。
加了关键字synchronize之后
package com.thread.Synchronized; /** * 线程同步 * --》synchronized关键字 * * 模拟一个多窗口售票的例子 * * @author hunjun */ public class TestSync implements Runnable{ private static int ticketNum = 200; public static void main(String[] args) { TestSync ts1 = new TestSync(); TestSync ts2 = new TestSync(); TestSync ts3 = new TestSync(); Thread t1 = new Thread(ts1,"窗口一"); Thread t2 = new Thread(ts2,"窗口二"); Thread t3 = new Thread(ts3,"窗口三"); t1.start(); t2.start(); t3.start(); } @Override public void run() { // TODO Auto-generated method stub try { while(ticketNum > 0){ Thread.sleep(2000); TestSync.saleTicket(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
/*在这里加了关键字synchronized*/ public static synchronized void saleTicket(){ if(ticketNum > 0){ //开始售票 System.out.println(Thread.currentThread().getName()+"售出第 "+ticketNum+" 张票。。"); ticketNum --; } } }
结果:
窗口三售出第 200 张票。。
窗口二售出第 199 张票。。
窗口一售出第 198 张票。。
窗口一售出第 197 张票。。
窗口二售出第 196 张票。。
窗口三售出第 195 张票。。
窗口一售出第 194 张票。。
窗口二售出第 193 张票。。
窗口三售出第 192 张票。。
总结:多线程是java中很重要的知识点,涉及很多编程的概念,比如还有死锁问题,线程池什么的。
请继续关注。。。。
如果您认为哪里有什么问题欢迎一起学习,沟通解决!!