黑马程序员________多线程的理论及应用学习笔记

来源:互联网 发布:软件开发成本核算表 编辑:程序博客网 时间:2024/05/17 09:05

 ------- android培训java培训、期待与您交流! ----------

 

       一个执行中的程序叫做进程。而每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。进程中的一个独立的控制单元就是线程。线程控制着进程的执行。一个进程至少有一个线程。

      

进程的特征有:

 

        动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。

 

  并发性:任何进程都可以同其他进程一起并发执行

 

  独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

 

    异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进

 

  结构特征:进程由程序、数据和进程控制块三部分组成。

 

  多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。

 

    线程与进程的区别可以归纳为以下几点:

 

  1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。

 

  2)通信:进程间通信ipc,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。

 

  3)调度和切换:线程上下文切换比进程上下文切换要快得多。

 

4)在多线程OS中,进程不是一个可执行的实体。

 

创建线程的第一种方法是建立一个类来继承Thread类,复写Thread类中的run方法,将线程中需要运行的代码存储在run方法中,然后调用线程的start方法,该方法可以启动线程并调用run方法。

 

       创建线程的第二种方法是建立一个类来实现Runnable接口àclass Demo implements Runnable,必须复写接口中的的无参方法run()。通过Thread类建立线程对象,将Runnable接口的子类对象作为实际参数传给Thread的构造函数àThread  t=new Thread(new Demo()); 。然后调用start()开启线程。

 

       由此可见,实现Runnable接口的方法避免了单继承的局限性。

 

       线程分为四个状态。分别为运行状态,冻结状态,消亡状态和临时状态。他们是通过一系列代码来改变状态的。从创建一个线程之后,start()使线程开始运行,由于cpu还要处理其他线程,所以当该线程没有cpu执行权的时候则处于临时状态,此时的线程处于运行状态和临时状态之间快速切换;如果遇到sleep或者wait则进入冻结状态,此时线程没有执行资格,直到sleep时间到或者被程序被notify唤醒之后,则线程进入临时状态和运行状态;当线程遇到stop或者运行到代码结束则线程进入消亡状态。wait()和notify()命令前面要加控制线程的锁。唤醒和等待必须是同一个锁。

 

       多线程的安全问题用java中的同步代码块来解决。格式synchronized(对象){需要被同步的代码}。同步的前提第一是必须有一个以上的的线程。第二必须是多个线程使用同一个锁。但是也有弊端,多个线程需要判断,较为消耗资源。如何找到需用同步代码分为三步:1明确哪些代码是多线程的运行代码。2明确共享数据。3明确多线程运行代码中哪些语句操作共享数据。同步的另一种表现形式是是将synchronized作为修饰符来修饰函数,则该函数具备同步。同步函数的锁是this。静态同步函数,使用的锁是该方法所在类的字节码文件对象,即类名.class。其中的一个小应用,懒汉式单利设计模式:

 

class Single{private Sigle(){}private static Single s=null;public static Single getInstance(){if (s==null){synchronized(Single.class){if(s==null)s=new Single();}}return s;}}


 

       同步函数嵌套同步函数,但是锁不同的话就会发生死锁现象。即synchronized (obj1){ synchronized (obj2){}}         synchronized (obj2){ synchronized (obj1){}}

                                   

       同步代码块中wait(),notify()方法,在线程得到对象o的锁旗标后,如果同步代码块中出现wait(),此时线程被放在对象o的等待线程池中,线程自动释放o的锁旗标,当另外线程执行了o的notify()方法后,线程可能会被从o的等待线程池中被释放出来,并且移动到等待线程对象o的锁旗标的线程池中,当线程得到锁旗标的时候就会往下执行。

 

       JDK1.5中提供了多线程解决方案。将同步函数Synchronized替换成Lock操作。将Object中的wait,notify,notifyAll,替换成了Condition对象的await,signal,signalAll,该对象可以Lock锁进行获取。Lock  lock=new  Reentrantlock();Condition condition_pro= lock.newcondition(); Condition condition_con=lock.newcondition();以上是通过lock对象中的newcondition方法建立了两个condition对象,就可以调用condition中的await,signal,signalAll方法。inerrupt方法为唤醒所有在冻结状态的线程。Lock的其中一个优势是可以把lock.unlock放在finally中执行,避免同步中的代码出现异常,而使锁得不到释放。另外一个重要优势就是一个锁上可以有多个condition。

 

setDaemon方法必须在线程启动前调用,标记该线程为守护线程,当正在运行的线程都为守护线程时,也就是前台线程结束后,Java虚拟机退出。在我们运行一个最简单的helloworld程序的时候,jvm其实就调用了两个线程,一个是main函数的主线程,另外一个线程则为jvm的垃圾回收机制,垃圾回收线程为守护线程,即后台线程,他会随着主线程的结束而结束。

 

遇到join方法的时候,主线程主动放弃执行权,处于冻结状态,等到调用线程结束,唤醒主线程,即把该线程和主线程合并为同一线程。亦可以在join方法传入一个值,代表主线程放弃执行权的毫秒数。setPriority方法为设置线程的执行优先级,可以用thread.MAX_PRIORITY和thread.MIN_PRIORITY来表示最高优先级和最低优先级。

 

       以下是一个多线程的例子。反应生产产品和消费产品。生产一个消费一个。但是生产者和消费者是随机的。

 

class Demo{public static void main(String[] args){Resourse res=new Resourse();Producer pro=new Producer(res);Consumer con=new Consumer(res);Thread t1=new Thread(pro);Thread t2=new Thread(con);t1.start();t2.start();}}class Resourse{private String name;private int count=1;private boolean flag=false;public synchronized void  set(String name){while(flag)///////////////////这里用while是因为如果被唤醒线程是自己需要重新判断flagtry{this.wait();} catch(Exception e){}this.name=name+"--"+count++;/////////////////////////自增来记录商品的编号System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);flag=true;this.notifyAll();}public synchronized void  out(){while(!flag)try{this.wait();} catch(Exception e){}System.out.println(Thread.currentThread().getName()+"..消费者......."+this.name);flag=false;this.notifyAll();}}class Producer implements Runnable{private Resourse res;Producer(Resourse res){this.res=res;}public void run(){while(true)res.set("商品");}}class Consumer implements Runnable{private Resourse res;Consumer(Resourse res){this.res=res;}public void run(){while(true)res.out();}}

原创粉丝点击