黑马程序员---Java基础学习笔记(多线程-前篇)

来源:互联网 发布:淘宝客服的感想 编辑:程序博客网 时间:2024/05/11 01:22
------------Android培训、Java培训、期待与您交流----------

1.进程和线程的定义和区别
    进程:正在进行的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
    线程:进程内部的一条执行路径或者一个控制单元。
    两者的区别:
一个进程至少有一个线程,进程在执行过程中拥有独立的内存单元,而多个线程共享内存。
    多线程:一个进程中有多个线程,称为多线程
2.实现多线程的方法:实现多线程可以通过继承Thread类和实现Runnable接口。

(1)继承Thread

步骤:1.定义一个线程类继承Thread

          2.复写Thread类中的run方法==>将自定义代码存储在子类run方法中,让子线程运行。
          3.调用线程的Thread方法==>两个作用:启动线程&调用run方法

        为什么运行结果每次都不同?
       因为多个线程都获取CPU的执行权,CPU执行到谁,谁就运行。需要注意的是:在某一个时刻,
       只能有一个程序在运行。(多核CPU除外) 只不过是CPU在做着快速切换,已达到看上去是同时运行的效果。
       我们可以形象的把多线程的运行看作是在互相抢夺CPU的执行权。
       这是CPU的一个特性:随机性。谁抢到CPU的资源谁就执行,至于运行多长时间,CPU说了算。
 
       为什么要覆盖Run方法? Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。

       start()和run()方法有什么区别?
       调用start方法方可启动线程,而run方法只是thread的一个普通方法,调用run方法不能实现多线程。
       start()方法:
       start()方法用来启动线程,实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个          线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片(执行权),就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个        线程的内容,Run方法运行结束,此线程随即终止。
       run()方法:
       run()方法只是Thread类的一个普通方法,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要等待run方法体执        行完毕后才可继续执行下面的代码,这样就没有达到多线程的目的。

class Demo extends Thread{private String name;Demo(String name){this.name = name;}public void run(){for(int i=0 ; i<50 ; i++)System.out.println("No."+name +" SubThread running===>"+i);}}public class ThreadIntro {public static void main(String[] args) {Demo d1 = new Demo("1");//创建好一个线程d1.start();//开启线程并执行该线程的run方法Demo d2 = new Demo("2");d2.start();//d.run();//仅仅是对象调用方法。并没有使用创建的线程for(int i=0 ; i<50 ; i++)System.out.println("MainThread running--->"+i);}}


        (2)实现Runnable接口;
        定义一个类,实现Runnable接口;
        覆盖接口的public void run()的方法,将线程的任务代码封装到run方法中;
        创建Runnable接口的子类对象

        将Runnabl接口的子类对象作为参数传递给Thread类的构造函数,创建Thread类对象 调用start()方法,启动线程。

class bank{private int total;public synchronized void add(int num){total += num;try {Thread.sleep(10);}catch (Exception e){e.printStackTrace();}System.out.println(Thread.currentThread().getName()+" Total:"+total);}}class client implements Runnable{private bank b = new bank();public void run(){for(int i = 0 ; i < 3 ; i++){b.add(100);}}}public class ThreadBankDemo {public static void main(String[] args) {client c = new client();Thread t1 = new Thread(c);Thread t2 = new Thread(c);t1.start();t2.start();new Thread(c).start();}}
3.多线程的单例设计模式:
保证某个类中内存中只有一个对象
饿汉式是类一加载进内存就创建好了对象。

//饿汉式单例加锁(General used in coding)class Singlee{private static final Singlee s = new Singlee();private Singlee(){}public static Singlee getInstance(){return s;}}

懒汉式则是类加载进内存的时候,对象还没有存在,只有调用了getInstance()方法时,对象才开始创建。懒汉式是延迟加载,如果多个线程同时操作懒汉式时就有可能出现线程安全问题,解决线程安全问题可以加同步来解决。

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

但是加了同步之后,每一次都要比较锁,效率就变慢了,所以可以加双重判断来提高程序效率。如将上述懒汉式的Instance函数改成同步:

//懒汉式单例加锁(延迟加载模式)class Single{private static Single s = null;private Single(){}public static Single getInstance(){if(s==null){synchronized(Single.class)//锁为该类所属的字节码类对象{if(s==null)s = new Single();}}return s;}}
------------Android培训、Java培训、期待与您交流----------