-------<a href="培训</a>、<a href="" ">java培训</a>期待与您交流。----------
黑马程序猿_2014 7月份 我对使用多线程的心得
本博客的题目就有些怪——2014 7月份 我对使用多线程的心得。加上日期,是由于我认为。在学习编程这样的纯思想上的技能。(有些技能是训练肌肉记忆,我认为编程是与之相对的技能)。对编程语言的理解与使用,假设不断地认真学习。理解也会在不断地变化,提高。
不同一时候期会有不同的认识,而且这样的改变会非常快。
常常有时候看也前自己的学习笔记会发现自己非常浅薄。但这些浅薄也正是自己变的深刻的台阶。所以我的这篇多线程使用心得客观上或许是非常浅薄的。但并最好还是碍我要将他写出来。
在使用多线程时。主要是环绕两个方面——线程的安全问题和线程间的通信问题。
线程的安全问题产生的原因:
多线程程序在执行时,不是每一个线程同一时候被执行,而是CPU在每一个线程间高速切换的执行着。它在这个线程上执行一会,又切到还有一个线程间执行会。
正是因为多线程的这样的执行机制导致了多线程的安全问题。
我们知道一个线程中。有些代码是要求必须完整一次性被CPU执行完的。不然就会出现故障。这由其表如今线程在操作共享数据的代码时。
举个卖票的样例。两个线程在卖票。车票号是共享的数据。用一个变量N来存储当前的票号。每一个线程取出当前票号作为售出车票的车号,然后再将N减去一,作为下次售出车票号。在程序运行时。如果线程一取出N,然后将该号的车票卖出,这时N减去一的代码还没运行,CPU就有又切到第二个线程。取出N,由于线程一并没有运行N减一的代码,所以它就取出了与线程一取出的同样号码的票号。结果就是。车站卖出了两张同样车票号的车票。
总结一下,多线程出现安全问题是由于线程中有要求被CPU完整一次性运行的代码。而这样的代码主要是操作共享数据的代码。
线程安全问题的解决就是同步。将须要被CPU完整一次性运行的代码放到同步代码块里,或是将其封装为同步方法方法。
这个怎样做到非常easy就不说了。
既然知道了多线程安全问题的解决办法了,接下来就是研究怎样写代码了。
先讲下多线程的启动。
很多视屏,书上都讲开启一个线程有两个方式。
可是我认为从本质上讲,开启线程就仅仅有一个方式。那就是调用Thread类对象的start()方法。
Start()方法内部是掉用了run方法。
之所以说有两种方式就在于这个run方法。Start()实际执行的run方法能够来源于两个地方。
一个是来源于继承Thread类复写其本身的run()还有一个是来源于Runnable子类的run()。
这个结论是依据源码发现的。
源码中。Thread的run方法是先推断其封装的Runnable类型成员变量是否为null。假设不为空就掉用它的run()方法。
第一种方式就是覆盖掉Thread的run 方法。让start()方法执行Thread的run()。
另外一种方式是向Thread的构造函数中传递一个实现了Runnable接口重写了run方法的类的实例。让start()执行runnable子类的run().
这两种方式我的理解是,事实上Thread类能够理解为一个启动线程的类,Runnable子类是一个存储线程执行代码的类。所以另外一种方式更符合java的OOP思想,启动线程类就负责启动线程。存储线程执行的代码类就存储线程的代码。各司其职。清晰了然。而第一种是一种简便的开启线程的方式。
回到正题,怎样编写涉及多线程 安全问题的多线程程序呢?
我们知道了多线程安全问题主要是由于线程中有操作共享数据的代码。而据我如今所知。
能够依据线程操作共享数据的代码是否同样。来分两种方式来设计程序。
第一种,对共享数据操作的代码同样。
当线程们要操作的共享数据的代码同样时能够这样设计。
将操作的共享数据的代码同步并放到一个Runnable子类的run方法中。
就用多线程卖票的样例来演示。
每一个线程线程对共享数据——车票,都是同样的操作方式。就是卖。
另外一种情况:线程对共享数据的操作代码不同。
设计步骤是:
a:将要共享的数据资源封装成单独的一个类。
将线程对共享数据的操作封装成该类的方法,一定要记得同步。
b:Runable接口的实现类。用构造函数传值的方式传入共享数据对象,在该类的run方法中完毕对共享数据的操作,调用共享数据对象中对应的方法就可以。有几种对共享数据的操作方式就写几个实现类。
用张老师的视屏中的一个样例演示。有四个线程对一个变量j的值进行操作。当中两个进行加一操作。两个进行减一操作。
多线程的通信:首先我问一个问题,为什么notif(), wait()方法写在同步语句块,同步函数中。能不写在里面吗?
多线程通信是要让线程与线程依据程序猿的意愿协作执行。
本质上讲,多线程程序在执行时,CPU在线程间的切换是随机的。所以哪个线程被执行也是随机的。而线程间的通信就是要线程按程序猿的意愿去获取或失去执行资格。线程的通信通过等待唤醒机制来完毕。notif(),wait()必须写在同步语句块或同步函数里。由于没有同步线程间得通信就没有了意义。由于线程间的通信就是让程序猿决定改线程何时等待,何时唤醒他线程。
假设notif()。wait()不放在同步里面。
CPU就会再线程间随意切换。那还谈什么程序猿控制一个线程何时获取或何时失去执行资格。
在实际开发中都是让A线程完整的做完某件事(完整的执行完某段代码)就让A线程唤醒B线程。自己等待,等B线程完整的做完某件事在唤醒A,自己等待。
总之,线程不须要同步,就没有通信的必要。
在写涉及到多线程通信的代码时,我的经验是先不考虑线程间通信问题。先依据上面涉及线程安全问题的思想写出代码,然后再在同步语句代码里加上有关多线程通信的代码就可以。
用消费者,生产者这一经典案例来演示线程间通信。
-------<a href="培训</a>、<a href="" ">java培训</a>期待与您交流!
----------