大数据之路week03--day05(线程 II)

今天,咱们就把线程给完完全全的结束掉,但是不是说,就已经覆盖了全部的知识点,可以说是线程的常见的问题及所含知识基本都包含。

1、多线程(理解)

  (1)JDK5以后的针对线程的锁定操作和释放操作

    Lock锁

  (2)死锁问题的描述和代码体现

    同步的弊端:

      A:效率低

      B:容易产生死锁

    死锁:

      两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待现象。

    举例:

      中国人和外国人吃饭的案例

      正常情况下:

        中国人:筷子两支

        外国人:刀和叉

      死锁情况下:

        中国人:筷子1支,刀一把。

        外国人:筷子1支,叉一把。

        (都在等待对方给自己的用具)

用代码怎么体现一个死锁问题?(面试题

创建一个锁类,有两把锁:

 1 package com.wyh.lock;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午8:27:03
 6 */
 7 public class MyLock {
 8     
 9     //定义两把锁
10     public static final Object objA = new Object();
11     public static final Object objB = new Object();
12 
13 }

创建线程类,重写run方法:

 1 package com.wyh.lock;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午8:28:17
 6 */
 7 public class DieLock extends Thread{
 8     private boolean flag;
 9     
10     
11     public DieLock(boolean flag) {
12         this.flag = flag;
13     }
14 
15     @Override
16     public void run() {
17         if(flag) {
18             synchronized(MyLock.objA) {
19                 System.out.println("if objA");//情况是当dl1走到这里等待锁B
20                 synchronized(MyLock.objB) {
21                     System.out.println("if objB");
22                 }
23             }
24         }else {
25             synchronized(MyLock.objB) {
26                 System.out.println("else objB");//当dl2走到这里等待锁A
27                 synchronized(MyLock.objA) {
28                     System.out.println("else objA");
29                 }
30             }
31         }
32     }
33     
34 }

编写测试类:

 1 package com.wyh.lock;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午8:33:50
 6 */
 7 public class DieLockDemo {
 8     public static void main(String[] args) {
 9         DieLock dl1 = new DieLock(true);
10         DieLock dl2 = new DieLock(false);
11         
12         dl1.start();
13         dl2.start();
14     }
15 
16 }

  (3)生产者和消费者多线程体现(线程间的通信问题)

    上一节我们写的售票程序并不符合实际情况。

      以学生作为资源来实现的

      资源类:student

      设置数据类:SetThread(生产者)

      获取数据类:GetThread(消费者)

      测试类:StudentDemo

      代码:

A:最基本的版本,只有一个数据。

Student类:

 1 package 生产者消费者01;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:02
 6 */
 7 public class Student {
 8     String name;
 9     int age;
10 
11 }

SetThread类:(为了保证多个线程是操作同一个学生,我们重写有参构造方法)

 1 package 生产者消费者01;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:35
 6 */
 7 public class StudentSetThread implements Runnable {
 8     private Student s ;
 9     
10     public StudentSetThread(Student s) {
11         this.s = s;
12     }
13 
14     @Override
15     public void run() {
16         s.name = "王友虎";
17         s.age = 22;
18     }
19 
20 }

SetThread类:

 1 package 生产者消费者01;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:04:46
 6 */
 7 public class StudentGetThread implements Runnable {
 8     private Student s ;
 9     
10     public StudentGetThread(Student s) {
11         this.s = s;
12     }
13 
14     @Override
15     public void run() {
16         System.out.println(s.name+"---"+s.age);
17     }
18 
19 }

测试类;

 1 package 生产者消费者01;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:05:35
 6 */
 7 public class StudentThreadDemo {
 8     public static void main(String[] args) {
 9         Student s = new Student();
10         StudentSetThread st = new StudentSetThread(s);
11         StudentGetThread sg = new StudentGetThread(s);
12         
13         Thread t1 = new Thread(st);
14         Thread t2 = new Thread(sg);
15         
16         t2.start();
17         t1.start();
18         
19     }
20 }

但是运行多次我们发现,有出现姓名为null或者年龄为0的情况出现,这是为什么?

 这是因为CPU进行的操作都是原子操作,有情况是当对年龄进行赋值,还没来得及对姓名赋值,下一个线程就进行输出。从而导致有null的情况,其他情况类推。

B:改进版本,给出了不同的数据。并加入了同步机制。

为了数据效果好一点,我们设置循环和判断,给出不同的值.

学生类:

 1 package 生产者消费者02;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:02
 6 */
 7 public class Student {
 8     String name;
 9     int age;
10 
11 }

SetThread类:

 1 package 生产者消费者02;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:35
 6 */
 7 public class StudentSetThread implements Runnable {
 8     private Student s ;
 9     private int x = 0;
10     
11     public StudentSetThread(Student s) {
12         this.s = s;
13     }
14 
15     @Override
16     public void run() {
17         while(true) {19                 if(x%2==0) {
20                     s.name = "王友虎";
21                     s.age = 22;
22                 }else {
23                     s.name = "李智恩";
24                     s.age = 20;
25                 }27             x++;
28         }
29         
30     }
31 
32 }

GetThread类:

 1 package 生产者消费者02;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:04:46
 6 */
 7 public class StudentGetThread implements Runnable {
 8     private Student s ;
 9     
10     public StudentGetThread(Student s) {
11         this.s = s;
12     }
13 
14     @Override
15     public void run() {
16         while(true) {18                 System.out.println(s.name+"---"+s.age);20         }
21         
22     }
23 
24 }

测试类:

 1 package 生产者消费者02;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:05:35
 6 * 
 7 * 解决线程安全的问题
 8 * 
 9 */
10 public class StudentThreadDemo {
11     public static void main(String[] args) {
12         Student s = new Student();
13         StudentSetThread st = new StudentSetThread(s);
14         StudentGetThread sg = new StudentGetThread(s);
15         
16         Thread t1 = new Thread(st);
17         Thread t2 = new Thread(sg);
18         
19         t2.start();
20         t1.start();
21         
22     }
23 }

运行结果:

 我们发现了问题

    1:同一个数据出现多次

        CPU的一点点时间片的执行权,就足够执行很多次

    2:姓名和年龄不匹配

        线程运行的随机性

很显然,我们这个改进还是存在线程安全的问题:

  怎么判断一个线程是不是安全的:

    1:是否是多线程环境  是

    2:是都有共享数据  是

    3:是否有多条语句操作共享数据  是

C:等待唤醒机制改进程序。让数据能够实现依次的出现

            wait()  :等待

            notify(): 唤醒单个线程

            notifyAll(): 唤醒多个线程

(上面这3个方法的调用必须是通过锁对象调用,而当我们使用的锁悐是任意锁,所以和没加锁区别不大,所以,这些方法必须定义在Object类中s)

对上面的进行解决:加锁,synchronized,并且通过等待唤醒机制进行操作。保证数据是依次出现的

注意:1、不同种类的线程都要加锁。   2、不同种类的线程加的锁必须是同一把。

学生类:

 1 package 生产者消费者03;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:02
 6 */
 7 public class Student {
 8     String name;
 9     int age;
10     boolean flag; //默认没有数据.false
11 }

SetThread类:

 1 package 生产者消费者03;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:35
 6 */
 7 public class StudentSetThread implements Runnable {
 8     private Student s ;
 9     private int x = 0;
10     
11     public StudentSetThread(Student s) {
12         this.s = s;
13     }
14 
15     @Override
16     public void run() {
17         while(true) {
18             synchronized(s) {
19                 if(s.flag) {
20                     try {
21                         s.wait();
22                     } catch (InterruptedException e) {
23                         e.printStackTrace();
24                     }
25                 }
26                 
27                 if(x%2==0) {
28                     s.name = "王友虎";
29                     s.age = 22;
30                 }else {
31                     s.name = "李智恩";
32                     s.age = 20;
33                 }
34                 
35                 //此时有数据
36                 s.flag = true;
37                 //唤醒线程
38                 s.notify(); //唤醒不代表立即执行,还需要争夺CPU执行权.
39                 
40             }  
41             x++;
42             
43             
44             
45         }
46         
47     }
48 
49 }

GetThread类:

 1 package 生产者消费者03;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:04:46
 6 */
 7 public class StudentGetThread implements Runnable {
 8     private Student s ;
 9     
10     public StudentGetThread(Student s) {
11         this.s = s;
12     }
13 
14     @Override
15     public void run() {
16         while(true) {
17             synchronized (s) {
18                 if(!s.flag) {
19                     try {
20                         s.wait();
21                     } catch (InterruptedException e) {
22                         e.printStackTrace();
23                     }
24                 }
25                 System.out.println(s.name+"---"+s.age);
26                 
27                 //消費了
28                 s.flag = false;
29                 //綫程
30                 s.notify();
31                 
32             }
33         }
34         
35     }
36 
37 }

测试类:

 1 package 生产者消费者03;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:05:35
 6 * 
 7 * 等待唤醒机制
 8 * 
 9 */
10 public class StudentThreadDemo {
11     public static void main(String[] args) {
12         Student s = new Student();
13         StudentSetThread st = new StudentSetThread(s);
14         StudentGetThread sg = new StudentGetThread(s);
15         
16         Thread t1 = new Thread(st);
17         Thread t2 = new Thread(sg);
18         
19         t2.start();
20         t1.start();
21         
22     }
23 }

D:资源唤醒机制的代码优化,

把数据及操作都写在了资源类中,同步方法实现。

学生类:

 1 package 生产者消费者04优化;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:02
 6 * 
 7 * 
 8 * 用同步方法来优化
 9 * 
10 */
11 public class Student {
12     private String name;
13     private int age;
14     private boolean flag; //默认没有数据.false
15     
16     
17     public synchronized void set(String name,int age) {
18         if(flag) {
19             try {
20                 this.wait();
21             } catch (InterruptedException e) {
22                 e.printStackTrace();
23             }
24         }
25         
26         this.name = name;
27         this.age = age;
28         
29         //修改
30         flag = true;
31         
32         //唤醒
33         this.notify(); 
34     }
35     
36     
37     public synchronized void get() {
38         if(!flag) {
39             try {
40                 this.wait();
41             } catch (InterruptedException e) {
42                 e.printStackTrace();
43             }
44         }
45         
46         System.out.println(this.name + "---" + this.age);
47         
48         //修改
49         flag = false;
50         
51         //唤醒
52         this.notify();
53     }
54     
55     
56     
57 }

SetThread类:

 1 package 生产者消费者04优化;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:03:35
 6 */
 7 public class StudentSetThread implements Runnable {
 8     private Student s ;
 9     private int x = 0;
10     
11     public StudentSetThread(Student s) {
12         this.s = s;
13     }
14 
15     @Override
16     public void run() {
17         while(true) {
18                 if(x%2==0) {
19                     s.set("王友虎", 22);
20                 }else {
21                     s.set("李智恩", 20);
22                 } 
23                 x++; 
24             }    
25         }
26 
27 }

GetThread类:

 1 package 生产者消费者04优化;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:04:46
 6 */
 7 public class StudentGetThread implements Runnable {
 8     private Student s ;
 9     
10     public StudentGetThread(Student s) {
11         this.s = s;
12     }
13 
14     @Override
15     public void run() {
16         while(true) {
17                 s.get();
18                 
19             }
20         }
21         
22     }

测试类:

 1 package 生产者消费者04优化;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午9:05:35
 6 * 
 7 * 等待唤醒机制
 8 * 
 9 */
10 public class StudentThreadDemo {
11     public static void main(String[] args) {
12         Student s = new Student();
13         StudentSetThread st = new StudentSetThread(s);
14         StudentGetThread sg = new StudentGetThread(s);
15         
16         Thread t1 = new Thread(st);
17         Thread t2 = new Thread(sg);
18         
19         t2.start();
20         t1.start();
21         
22     }
23 }

线程的状态转换图:

  

  (4)线程组(用实现Runnable接口的方式举例)

 1 package 线程组1;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午10:30:51
 6 */
 7 public class MyRunnable implements Runnable{
 8 
 9     @Override
10     public void run() {
11         System.out.println(Thread.currentThread().getName());
12         
13         
14     }
15     
16 }

测试类:

 1 package 线程组1;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午10:31:37
 6 */
 7 public class MyRunnableDemo {
 8     public static void main(String[] args) {
 9         ThreadGroup tg = new ThreadGroup("这是一个新的线程组");
10         
11         MyRunnable mr = new MyRunnable();
12         
13         Thread t1 = new Thread(tg,mr,"王友虎");
14         Thread t2 = new Thread(tg,mr,"李智恩");
15         
16         
17         System.out.println(t1.getThreadGroup().getName());
18         System.out.println(tg.getName());
19     }
20 
21 }

  (5)线程池

    程序启动一个新的线程成本是比较高的,因为它涉及到要与操作系统进行交互,而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

      1、线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

      2、在JDK5之前,我们必须手动实现自己的线程池,从JDk5开始,Java内置支持线程池。

    如何实现线程池的代码呢?

      1、创建一个线程对象,控制要创建几个线程对象。

        public static ExecutorService newFixedThreadPool(int nThread)

      2、这种线程池的线程可以执行:

        可以执行Runnable对象或者Callable对象代表的线程

        做一个类实现Runnable接口。

      3、调用下面的方法即可

        Future submit(Runnable task)

        <T> future<T> submit(Callable<T> task)

      4、我就要结束,可以吗? 可以。

        shutdown()

实现Runnable接口:

 1 package 线程池;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 上午11:08:38
 6 */
 7 public class MyRunnable implements Runnable{
 8 
 9     @Override
10     public void run() {
11         for(int x = 0;x<500;x++) {
12             System.out.println(Thread.currentThread().getName()+":"+x);
13         }
14         
15     }
16 
17 }

测试类:

 1 package 线程池;
 2 
 3 import java.util.concurrent.Executor;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6 
 7 /** 
 8 * @author WYH
 9 * @version 2019年11月23日 上午11:09:57
10 * 
11 * 线程池的创建
12 */
13 public class ExecutorsDemo {
14     public static void main(String[] args) {
15         //创建线程池
16         ExecutorService pool = Executors.newFixedThreadPool(2);
17         ExecutorService pool1 = Executors.newCachedThreadPool();
18         
19         pool.submit(new MyRunnable());
20         pool.submit(new MyRunnable());
21         
22         pool1.submit(new MyRunnable());
23         pool1.submit(new MyRunnable());
24         pool1.submit(new MyRunnable());
25         
26         pool.shutdown();
27         pool1.shutdown();
28         
29     }
30 
31 }

  (6)多线程实现的第三种方案

MyCallable类:

 1 package com.wyh.callable;
 2 
 3 import java.util.concurrent.Callable;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月23日 下午2:29:25
 8 */
 9 public class MyCallable implements Callable {
10 
11     @Override
12     public Object call() throws Exception {
13         for(int x = 0;x<500;x++) {
14             System.out.println(Thread.currentThread().getName()+":"+x);
15         }
16         return null;
17     }
18 
19 }

测试类:

 1 package com.wyh.callable;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 /** 
 7 * @author WYH
 8 * @version 2019年11月23日 下午2:30:21
 9 * 
10 * 创建线程的第三种方式
11 */
12 public class MyCallableDemo {
13     public static void main(String[] args) {
14         //创建线程池
15         ExecutorService pool = Executors.newFixedThreadPool(2);
16         
17         pool.submit(new MyCallable());
18         pool.submit(new MyCallable());
19         
20         pool.shutdown();
21     }
22 
23 }

  (6_2)Callable的案例(计算1+....的总和 线程池实现)

Runnable类:

 1 package com.wyh.callable案例1;
 2 
 3 import java.util.concurrent.Callable;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月23日 下午2:29:25
 8 */
 9 public class MyCallable implements Callable<Integer> {
10     private int number;
11     
12     public MyCallable(int number) {
13         this.number = number;
14     }
15     
16 
17     @Override
18     public Integer call() throws Exception {
19         int sum =0;
20         for(int x = 1;x<=number;x++) {
21             sum += x;
22 //            System.out.println(Thread.currentThread().getName()+":"+sum);
23         }
24 //        System.out.println(Thread.currentThread().getName()+":"+sum);
25         return sum;
26     }
27 
28 }

测试类:

 1 package com.wyh.callable案例1;
 2 
 3 import java.beans.FeatureDescriptor;
 4 import java.util.concurrent.ExecutionException;
 5 import java.util.concurrent.ExecutorService;
 6 import java.util.concurrent.Executors;
 7 import java.util.concurrent.Future;
 8 
 9 /** 
10 * @author WYH
11 * @version 2019年11月23日 下午2:30:21
12 * 
13 * 创建线程的第三种方式
14 */
15 public class MyCallableDemo {
16     public static void main(String[] args) throws InterruptedException, ExecutionException {
17         //创建线程池
18         ExecutorService pool = Executors.newFixedThreadPool(3);
19         
20         Future<Integer> f1 = pool.submit(new MyCallable(50));
21         Future<Integer> f2 = pool.submit(new MyCallable(100));
22         Future<Integer> f3 = pool.submit(new MyCallable(200));
23         
24         int i1 = f1.get();
25         int i2 = f2.get();
26         int i3 = f3.get();
27                 
28         
29         System.out.println(i1);
30         System.out.println(i2);
31         System.out.println(i3);
32         
33         
34         pool.shutdown();
35     }
36 
37 }

  (7)多线程的面试题

    a:多线程有几种实现方案,分别是哪几种?

      两种。(面试答2种

        继承Thread类

        实现Runnable接口

        扩展一种,实现Callable接口,这个要和线程池结合使用。

    b:同步有几种方式,分别是是什么?

      两种。

        同步代码块  锁是任意对象锁

        同步方法   锁是this

        同步静态方法  锁是当前类的二进制字节码文件

    c:启动一个线程是run()还是start()?它们的区别?

      start()

        run():封装了被线程执行的代码块,直接调用仅仅是一个普通方法的调用

        start():启动线程,并由JVM自动调用run()方法

    d:sleep()和wait()方法的区别

      sleep():必须指定时间,不释放锁。

      wait():可以不指定时间,也可以指定时间,但是它释放锁。

    e:为什么wait(), notify(), notifyAll()等方法都定义在Object类中?

      因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。而Object代表任意对象,所以,定义在里面。

    f:线程的生命周期图(如上)

      新建 -- 就绪 -- 运行 -- 死亡

      新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡

2、设计模式(理解)

  (1)面试对象的常见设计原则

      单一职责原则

      开闭原则

      里氏替换原则

      依赖注入原则

      接口分离原则

      迪米特原则

  (2)设计模式概述和分类

    A:经验的总结

    B:三类:

      创建型

      结构型

      行为型

  (3)改进的设计模式

    A:简单工厂模式

 Animal类:

 1 package 工厂设计模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午4:36:06
 6 */
 7 public abstract class Animal {
 8     public abstract void eat();
 9 
10 }
Animal
 1 package 工厂设计模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午4:37:44
 6 */
 7 public class AnimalFactory {
 8     private AnimalFactory(){
 9         
10     }
11     
12     public static Animal CreateAnimal(String type) {
13         if(type.equals("dog")) {
14             return new Dog();
15         }else if(type.equals("cat")) {
16             return new Cat();
17         }else {
18             return null;
19         }
20     }
21 
22 }
AnimalFactory
 1 package 工厂设计模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午4:37:16
 6 */
 7 public class Cat extends Animal {
 8 
 9     @Override
10     public void eat() {
11         System.out.println("猫吃鱼");
12 
13     }
14 
15 }
Cat
 1 package 工厂设计模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午4:36:45
 6 */
 7 public class Dog extends Animal {
 8 
 9     @Override
10     public void eat() {
11         System.out.println("狗吃肉");
12         
13 
14     }
15 
16 }
Dog
 1 package 工厂设计模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午4:41:54
 6 */
 7 public class FactoryDemo {
 8     public static void main(String[] args) {
 9         Animal a = AnimalFactory.CreateAnimal("dog");
10         a.eat();
11         Animal b = AnimalFactory.CreateAnimal("cat");
12         b.eat();
13         
14         Animal c = AnimalFactory.CreateAnimal("pig");
15         if(c != null) {
16             c.eat();
17         }else {
18             System.out.println("对不起,该工厂无法造该对象.");
19         }
20         
21         
22         
23     }
24 
25 }
FactoryDemo

    B:工厂方法模式

 1 package 工厂方法模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午5:18:40
 6 */
 7 public abstract class Animal {
 8     public abstract void eat();
 9 
10 }
Animal
 1 package 工厂方法模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午5:19:23
 6 */
 7 public interface Factory {
 8     public abstract Animal CreateAnimal();
 9 
10 }
Factory
 1 package 工厂方法模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午5:20:39
 6 */
 7 public class Dog extends Animal {
 8 
 9     @Override
10     public void eat() {
11         System.out.println("狗吃肉");
12 
13     }
14 
15 }
Dog
 1 package 工厂方法模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午5:22:01
 6 */
 7 public class DogFactory implements Factory {
 8 
 9     @Override
10     public Animal CreateAnimal() {
11         return new Dog();
12     }
13 
14 }
DogFactory
 1 package 工厂设计模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午4:37:16
 6 */
 7 public class Cat extends Animal {
 8 
 9     @Override
10     public void eat() {
11         System.out.println("猫吃鱼");
12 
13     }
14 
15 }
Cat
 1 package 工厂方法模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午5:23:46
 6 */
 7 public class CatFactory implements Factory {
 8 
 9     @Override
10     public Animal CreateAnimal() {
11         return new Cat();
12     }
13 
14 }
CatFactory
 1 package 工厂方法模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午5:20:03
 6 */
 7 public class FactoryDemo {
 8     public static void main(String[] args) {
 9         //我需要狗
10         Factory f = new DogFactory();
11         Animal a = f.CreateAnimal();
12         a.eat();
13         
14         //我需要猫
15         f = new CatFactory();
16         Animal a1 = f.CreateAnimal();
17         a1.eat();
18         
19     }
20 
21 }
FactoryDemo

    C:单例模式(掌握)

        a:饿汉式

Student类:

 1 package 单例模式;
 2 
 3 /**
 4  * @author WYH
 5  * @version 2019年11月23日 下午6:20:40
 6  */
 7 public class Student {
 8     // 将构造方法私有
 9     private Student() {
10 
11     }
12 
13     // 自己创建一个对象
14     // 静态方法只能访问静态的成员变量,加static
15     // 为了不让外界随意改动这个对象,我们将他私有化
16     private static Student s = new Student();
17 
18     // 提供一个方法给外界进行访问到这个对象
19     public static Student getStudent() {
20         return s;
21     }
22 
23 }

测试类:

 1 package 单例模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午6:20:47
 6 * 
 7 * 单例模式:保证类在内存中指存在一个对象
 8 * 饿汉式
 9 * 
10 */
11 public class StudentDemo1 {
12     public static void main(String[] args) {
13         
14         Student s1 = Student.getStudent();
15         Student s2 = Student.getStudent();
16         
17         System.out.println(s1 == s2);
18     }
19 
20 }

        b:懒汉式

Teacher类:

 1 package 单例模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午6:32:09
 6 * 
 7 * 懒汉式
 8 */
 9 public class Teacher {
10     private Teacher() {
11         
12     }
13     
14     private static Teacher teacher = null;
15     
16     public synchronized static Teacher getTeacher() {
17         if(teacher == null) {
18             teacher = new Teacher();
19         }
20         
21         return teacher;
22     }
23 
24 }

测试类:

 1 package 单例模式;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月23日 下午6:34:12
 6 */
 7 public class TeacherDemo {
 8     public static void main(String[] args) {
 9         Teacher t1 = Teacher.getTeacher();
10         Teacher t2 = Teacher.getTeacher();
11         
12         System.out.println(t1 == t2);
13         System.out.println(t1);
14         System.out.println(t2);
15         
16         
17     }
18 
19 }

(注意:面试的时候写懒汉式,开发的时候写饿汉式,因为饿汉式不存在线程安全问题)

  (4)Runtime

      JDK提供的一个单例模式应用的类

      还可以通过dos命令。

例子:

 1 package 单例模式;
 2 
 3 import java.io.IOException;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月23日 下午6:43:36
 8 * 
 9 * 饿汉式的一个类的例子
10 * 
11 * 
12 */
13 public class RunTimeDemo {
14     public static void main(String[] args) throws IOException {
15         Runtime r = Runtime.getRuntime();
16 //        r.exec("calc"); //调出计算器
17 //        r.exec("shutdown -s -t 10000");
18         r.exec("shutdown -a");
19     }
20 }
21 
22 /*
23  * 源码:
24  * 
25  * class Runtime{
26  *      private Runtime() {}
27  *      private static Runtime currentRuntime = new Runtime();
28  *      public static Runtime getRuntime() {
29  *               return currentRuntime;
30  *      }
31  * 
32  * }
33  */

猜你喜欢

转载自www.cnblogs.com/wyh-study/p/11920653.html
ii