一、线程的同步

在多线程程序中,它们多个线程之间是共享一块内存的。

当某个线程正在读取该内存块的信息时,并在修改内存信息的同时,并在此发生意外,如:阻塞,如果有别的线程也进来访问这块内存,并且也要修改该内存块的信息,这是就会发生意想不到的错误。

比如:你有一个银行账户,账户里面有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中很重要的知识点,涉及很多编程的概念,比如还有死锁问题,线程池什么的。

请继续关注。。。。

如果您认为哪里有什么问题欢迎一起学习,沟通解决!!

 

posted on 2017-04-11 18:34  HunJun  阅读(247)  评论(0编辑  收藏  举报