多线程及其同步

 

 

        之前学习过线程,但并不是太深入,遗留的有一些问题。因为大致看了一下后面张老师的7k交通灯的那个案例,里面要用到多线程,考虑到自己线程方面的基本功并不扎实,所以现在回过头来再学习线程。 毕老师的java课讲得很生动,在学习过程中自己又进步了很多。

       

        线程的创建有两种方法,一种是继承Thread类,另一种是实现Runnable接口。但是归根结底都是用Thread类创建线程,实现了Runnable接口的实体类并不能直接创建线程,还是要用Thread类来创建线程。Thread类有一个构造方法Thread(Runnable target),意思就是可以接收一个Runnable类型的对象,这也是创建线程要实现Runnable接口的原因。

       

 
 
 
 
         因为Runnable子类里的run方法所属的对象并不是线程对象,而是Runnable对象,要把Runnable对象传给Thread类。这里我就在想,那随便一个类,不实现Runnable接口,只要里面写了run方法,再把对象传给Thread的构造函数不就行了。但马上就被我自己否定了,因为Thread类没有Thread(Object target)这样一个构造函数用来接收任一对象。截止写博时我还不知道,为什么Thread类没有Thread(Object target)这样一个构造方法,难道Runnable接口还有其他的作用?
 
 
 
        另一问题是,在售票的例子里面,如果用继承Thread类的方法创建线程,那么在创建多个线程对象时,每创建一个线程对象,那个线程对象就拥有了一个票数的变量,而当通过实现Runnable接口创建线程类时,由于只创建了一个Runnable接口实现类对象,用这一个对象创建了几个线程对象,所以票数变量只有一份,这样的话就保证了数据的安全性。
        
 
 
 
 
 
        在之前的java学习中我不喜欢查文档,或者说没有查文档的习惯,遇到新的方法,第一反应就是百度。在听毕老师课的过程中,讲到一个新的API及其方法时,他都会通过查文档来讲。java的API太多,不想C语言,java很多东西是写好放在类库中,程序员可以直接拿来用,这就要求java编程者有查阅文档的习惯。在以后的学习中,我要尽量的养成查文档的习惯,并积累学习文档的经验。
 
        在API文档中可以看到,Thread类其实也是Runnable接口的实现类,这说明,Thread类中的run方法其实并不是自己独有的,而是覆盖Runnable接口中的run方法。
 
 
 
 
          当在run方法中让线程睡眠时,要处理异常,因为sleep方法有可能会产生异常。处理异常一般有两种方法:throw或者catch,但在这里,只能catch,不能throw。因为这里的run方法是override Runnable接口的,覆盖是有要求的,覆盖的方法必须和被覆盖的方法除方法体外完全一样,Runnable接口的run方法没有throw异常,所以实现类里的run方法也必须不能throw异常。这虽然是理所当然的,但在平时写程序的过程中,大概不会注意这一点,在这里加深了记忆,避免以后犯这样的错。
 
 
         再说线程同步,线程同步是为多线程共享数据安全性设计的,拿一个例子来说,还用前面的那个售票系统。每次执行买票行为之前,先要判断是否还有票,没票就不能卖了,问题来了,当只剩下1张票时,第一个售票窗口的线程判断后得知还有票,于是就进入售票页面,就在此时,买票的人还没按确认买票,票数自然没有自减,还是1,第二个窗口又有人来买票,第二个线程判断票数也是1,自然也就能进入售票页面。这样的情况,在春运期间是绝对会遇到的,同时买票的何止是两个人。所以如果不采取措施,就肯定会出问题。线程同步的关键字synchronized修饰的不是方法,而是对象,同步的不是类,不是方法,而是代码块,这一点需要注意。也就是,你没必要在一个方法前面加上synchronized关键字,只要在用到共享数据的语句前加上synchronized处理这些句子就行了。
 
 
 
         在使用synchronized时要给它一个对象参数,如果在参数列表中直接new一个对象,我发现synchronized起不了作用。而在前面声明并实例化一个对象,再把这个对象作为synchronized的参数,则同步就能起作用。
         
 
                                  如图,尽管使用了synchronized进行同步,但还是打印量负数
 
 
 
 
                               这样才实现了同步
         
         同步在什么时候用呢,是不是只要是多线程 ,就都用同步?非也。
       “有些代码需要同步,有些代码不需要同步”。这是同步的真正意义所在,明白这句话就不会产生我之前遇到的困惑:同步就是保证代码在一个时间段只能由一个线程执行,这样的话不就和单线程一样了吗? 这个问题困扰过我一段时间,现在明白了,要执行的代码很多,并非所有的要执行的代码都得放在同步里面,只要把用到共享数据的代码放在同步里边就行了,这样的好处是,虽然有共享数据的代码还是“单线程”,但是其他要执行的代码是多线程,可以同时执行。
 
 
         使用同步百益无一害吗,答案是否定的。
         线程执行到使用synchronized的地方时,会先判断标志锁是否打开,打开才执行里面的代码,每次执行到这个地方都会进行判断,这是很耗费cpu资源的。
         线程同步并非一定要用在共享数据的代码块,当共享数据的代码块不会出现安全问题时,就可以不用同步。拿售票系统来说,安全问题并非时刻都有,只有在票数只剩下很少的时候才会出现安全问题。基于这一点,我想到了一个方法,就是在票数足够多的情况下,不使用同步,当票数剩余不多时,才开始使用同步。
代码如下:
 
 
 
         到这里对于线程的理解又深入了许多,每次的进步都能带来喜悦,继续努力。

 

         

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值