黑马程序员_java语言_多线程和设计模式

来源:互联网 发布:最好的广告拦截软件 编辑:程序博客网 时间:2024/05/17 17:55

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

###17.01_多线程(多线程方法)
方法的介绍:
  唤醒线程对象的方法:

public final void notifyAll()
   唤醒在此对象监视器(锁对象)上等待的所有线程。
   当前线程必须拥有此对象监视器(锁对象)。
   如何将一个线程进入等待状态呢?
    线程通过调用其中一个 wait 方法,在对象的监视器(锁对象)上等待
  public final void notify()
   唤醒在此对象监视器(锁对象)上等待的单个线程。
   如果所有线程都在此对象上(锁对象)等待,则会选择唤醒其中一个线程。
   选择是任意性的
   当前线程必须拥有此对象监视器(锁对象)。


  
    
  public final void wait()
   在其他线程调用此对象(锁对象)的 notify() 方法或 notifyAll() 方法前,导致当前线程等待
   当前线程必须拥有此对象监视器(锁对象)。
   然后该线程将等到重新获得对监视器的所有权后才能继续执行。说明当前线程等待的时候,会释放锁对象
   
  public final void wait(long timeout) 毫秒
  public final void wait(long timeout, int nanos)毫秒, 纳秒
   在其他线程调用此对象(锁对象)的 notify() 方法或 notifyAll() 方法前,导致当前线程等待
   或者超过指定的时间量前,导致当前线程等待。
   如果超过了指定的时间量,线程会自定醒来
   当前线程必须拥有此对象监视器(锁对象)。
   然后该线程将等到重新获得对监视器的所有权后才能继续执行。说明当前线程等待的时候,会释放锁对象
  
  public static void sleep(long millis) 毫秒
   在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
   该线程不丢失任何监视器的所属权。 不会释放锁对象
  public static void sleep(long millis, int nanos) 毫秒, 纳秒
   在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行)
   该线程不丢失任何监视器的所属权。 不会释放锁对象

其实这些都属于线程通信,我们可以通过图例表示:
   
 sleep() 与 wait()的区别?
  sleep:
   时间到后醒来
   释放CPU执行权, 但是 不释放锁对象
  wait: 
   可以通过 notify() 方法或 notifyAll() 唤醒
   释放CPU执行权, 同时释放锁对象
  ###17.02_多线程(单例设计模式)
单例设计模式:保证类在内存中只有一个对象。

如何保证类在内存中只有一个对象呢?
    * (1)控制类的创建,不让其他类来创建本类的对象。private
    * (2)在本类中定义一个本类的对象。Singleton s;
    * (3)提供公共的访问方式。  public static Singleton getInstance(){return s}
单例写法两种:
    * (1)饿汉式 :

  1: 创建一个类
  2: 构造方法私有
  3: 在当前类中, 创建一个当前类对象,并私有
  4: 在当前类中,提供一个public方法,用来获取到创建好的对象

      开发用这种方式:

<span style="font-size:14px;">            //饿汉式            class Singleton {                //1,私有构造函数                private Singleton(){}                //2,创建本类对象                private static Singleton s = new Singleton();                //3,对外提供公共的访问方法                public static Singleton getInstance() {                    return s;                }                                public static void print() {                    System.out.println("11111111111");                }            }</span>

 * (2)懒汉式:

   1: 创建一个类
   2: 构造方法私有
   3: 在当前类中,创建一个当前类对象的引用,不进行new操作
   4: 在当前类中,提供一个public方法
    判断,如果是第一次使用
     是: 创建对象
     否: 使用创建好的对象
  面试题的考点:
  1: 不是上来就new对象
  2: 方法中的if判断
  3: 多线程安全问题 (同步)

 面试写这种方式。多线程的问题?

<span style="font-size:14px;"> //懒汉式,单例的延迟加载模式            class Singleton {                //1,私有构造函数                private Singleton(){}                //2,声明一个本类的引用                private static Singleton s;                //3,对外提供公共的访问方法                public static Singleton getInstance() {                    if(s == null)                        //线程1,线程2                        s = new Singleton();                    return s;                }                                public static void print() {                    System.out.println("11111111111");                }            }</span>

###17.03_多线程(Runtime类)
Runtime类是一个单例类

<span style="font-size:14px;">  Runtime r = Runtime.getRuntime();            //r.exec("shutdown -s -t 300");        //300秒后关机            r.exec("shutdown -a");                //取消关机</span>

###17.04_设计模式(工厂模式)

* 简单工厂模式概述
  又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
  优点
   客户端不需要在负责对象的创建,从而明确了各个类的职责
  缺点
   这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护

我们用图例表示一下:###17.05_多线程(两个线程间的通信)
1.什么时候需要通信
    * 多个线程并发执行时, 在默认情况下CPU是随机切换线程的
    * 如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
2.怎么通信
    * 如果希望线程等待, 就调用wait()
    * 如果希望唤醒等待的线程, 就调用notify();
    * 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用

###17.06_多线程(三个或三个以上间的线程通信)
多个线程通信的问题
    * notify()方法是随机唤醒一个线程
    * notifyAll()方法是唤醒所有线程
    * JDK5之前无法唤醒指定的一个线程
    * 如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件

我们用图例表示:
###17.07_多线程(JDK1.5的新特性互斥锁)
1.同步
    * 使用ReentrantLock类的lock()和unlock()方法进行同步
2.通信
    * 使用ReentrantLock类的newCondition()方法可以获取Condition对象
    * 需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
    * 不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

###17.08_多线程(线程组的概述和使用)
A:线程组概述
    * Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
    * 默认情况下,所有的线程都属于主线程组。
        * public final ThreadGroup getThreadGroup()//通过线程对象获取他所属于的组
        * public final String getName()//通过线程组对象获取他组的名字
    * 我们也可以给线程设置分组
        * 1,ThreadGroup(String name) 创建线程组对象并给其赋值名字
        * 2,创建线程对象
        * 3,Thread(ThreadGroup?group, Runnable?target, String?name) 
        * 4,设置整组的优先级或者守护线程
    * B:案例演示

        * 线程组的使用,默认是主线程组

<span style="font-size:14px;">  MyRunnable mr = new MyRunnable();        Thread t1 = new Thread(mr, "张三");        Thread t2 = new Thread(mr, "李四");        //获取线程组        // 线程类里面的方法:public final ThreadGroup getThreadGroup()        ThreadGroup tg1 = t1.getThreadGroup();        ThreadGroup tg2 = t2.getThreadGroup();        // 线程组里面的方法:public final String getName()        String name1 = tg1.getName();        String name2 = tg2.getName();        System.out.println(name1);        System.out.println(name2);        // 通过结果我们知道了:线程默认情况下属于main线程组        // 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组        System.out.println(Thread.currentThread().getThreadGroup().getName());</span>

 * 自己设定线程组

<span style="font-size:14px;">// ThreadGroup(String name)        ThreadGroup tg = new ThreadGroup("这是一个新的组");        MyRunnable mr = new MyRunnable();        // Thread(ThreadGroup group, Runnable target, String name)        Thread t1 = new Thread(tg, mr, "张三");        Thread t2 = new Thread(tg, mr, "李四");                System.out.println(t1.getThreadGroup().getName());        System.out.println(t2.getThreadGroup().getName());                //通过组名称设置后台线程,表示该组的线程都是后台线程        tg.setDaemon(true);</span>

###17.09_多线程(线程池的概述和使用)
A:线程池概述
    * 程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
B:内置线程池的使用概述
    * JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
        * public static ExecutorService newFixedThreadPool(int nThreads)
        * public static ExecutorService newSingleThreadExecutor()
        * 这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
        * Future<?> submit(Runnable task)
        * <T> Future<T> submit(Callable<T> task)
    * 使用步骤:
        * 创建线程池对象
        * 创建Runnable实例
        * 提交Runnable实例
        * 关闭线程池
    * C:案例演示

<span style="font-size:14px;"> * 提交的是Runnable*         // public static ExecutorService newFixedThreadPool(int nThreads)        ExecutorService pool = Executors.newFixedThreadPool(2);        // 可以执行Runnable对象或者Callable对象代表的线程        pool.submit(new MyRunnable());        pool.submit(new MyRunnable());        //结束线程池        pool.shutdown();</span>

###17.10_多线程(多线程程序实现的方式3)
提交的是Callable
多线程程序实现的方式3的好处和弊端
    * 好处:
        * 可以有返回值
        * 可以抛出异常
        
    * 弊端:
        * 代码比较复杂,所以一般不用

案例:

<span style="font-size:14px;">*         // 创建线程池对象        ExecutorService pool = Executors.newFixedThreadPool(2);        // 可以执行Runnable对象或者Callable对象代表的线程        Future<Integer> f1 = pool.submit(new MyCallable(100));        Future<Integer> f2 = pool.submit(new MyCallable(200));        // V get()        Integer i1 = f1.get();        Integer i2 = f2.get();        System.out.println(i1);        System.out.println(i2);        // 结束        pool.shutdown();        public class MyCallable implements Callable<Integer> {            private int number;                    public MyCallable(int number) {                this.number = number;            }                    @Override            public Integer call() throws Exception {                int sum = 0;                for (int x = 1; x <= number; x++) {                    sum += x;                }                return sum;            }                }</span>
<span style="font-size:14px;"></span> 

###17.11_设计模式(简单工厂模式概述和使用)
A:简单工厂模式概述
    * 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
B:优点
    * 客户端不需要在负责对象的创建,从而明确了各个类的职责
C:缺点
    * 这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护
D:案例演示
    * 动物抽象类:public abstract Animal { public abstract void eat(); }
    * 具体狗类:public class Dog extends Animal {}
    * 具体猫类:public class Cat extends Animal {}
    * 开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。

<span style="font-size:14px;">   public class AnimalFactory {            private AnimalFactory(){}                    //public static Dog createDog() {return new Dog();}            //public static Cat createCat() {return new Cat();}                    //改进            public static Animal createAnimal(String animalName) {                if(“dog”.equals(animalName)) {}                else if(“cat”.equals(animale)) {                        }else {                    return null;                }            }        } </span>

###17.12_设计模式(工厂方法模式的概述和使用)
A:工厂方法模式概述
    * 工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
B:优点
    * 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
C:缺点
    * 需要额外的编写代码,增加了工作量
D:案例演示

        动物抽象类:public abstract Animal { public abstract void eat(); }
        工厂接口:public interface Factory {public abstract Animal createAnimal();}
        具体狗类:public class Dog extends Animal {}
        具体猫类:public class Cat extends Animal {}

        开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。发现每次修改代码太麻烦,用工厂方法改进,针对每一个具体的实现提供一个具体工厂。

<span style="font-size:14px;"> 狗工厂:public class DogFactory implements Factory {            public Animal createAnimal() {…}                }        猫工厂:public class CatFactory implements Factory {            public Animal createAnimal() {…}                }  </span>

 

0 0
原创粉丝点击