多线程中的设计模式
1.设计模式(简单工厂模式概述和使用)
- A:简单工厂模式概述
- 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
- B:优点
- 客户端不需要在负责对象的创建,从而明确了各个类的职责
- C:缺点
- 这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护
- D:案例演示
- 动物抽象类:public abstract Animal { public abstract void eat(); }
- 具体狗类:public class Dog extends Animal {}
- 具体猫类:public class Cat extends Animal {}
- 开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。
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;
}
}
}
案例:
1. package com.boya.simplefactory;
2.
3. public abstract class Animal {
4. public abstract void eat();
5. }
6. package com.boya.simplefactory;
7.
8. public class Dog extends Animal {
9.
10. @Override
11. public void eat() {
12. System.out.println("狗吃肉");
13. }
14.
15. }
1. package com.boya.simplefactory;
2.
3. public class Cat extends Animal {
4.
5. @Override
6. public void eat() {
7. System.out.println("猫吃鱼");
8. }
9.
10. }
1. package com.boya.simplefactory;
2.
3. public class AnimalFactory {
4. /*public static Dog createDog() {
5. return new Dog();
6. }
7.
8. public static Cat createCat() {
9. return new Cat();
10. }*/
11.
12. //发现方法会定义很多,复用性太差
13. //改进
14. public static Animal createAnimal(String name) {
15. if("dog".equals(name)) {
16. return new Dog();
17. }else if("cat".equals(name)) {
18. return new Cat();
19. }else {
20. return null;
21. }
22. }
23. }
1. package com.boya.simplefactory;
2.
3. public class Test {
4.
5. /**
6. * @param args
7. */
8. public static void main(String[] args) {
9. //Dog d = AnimalFactory.createDog();
10.
11. Dog d = (Dog) AnimalFactory.createAnimal("dog");
12. d.eat();
14. Cat c = (Cat) AnimalFactory.createAnimal("cat");
15. c.eat();
16. }
17.
18. }
2:设计模式(工厂方法模式的概述和使用)
- 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 {} 开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。发现每次修改代码太麻烦,用工厂方法改进,针对每一个具体的实现提供一个具体工厂。 狗工厂:public class DogFactory implements Factory { public Animal createAnimal() {…} } 猫工厂:public class CatFactory implements Factory { public Animal createAnimal() {…} }
案例:
1. package com.boya.factorymethod;
2.
3. public abstract class Animal {
4. public abstract void eat();
5. }
1. package com.boya.factorymethod;
2.
3. public class Cat extends Animal {
4.
5. @Override
6. public void eat() {
7. System.out.println("猫吃鱼");
8. }
9.
10. }
1. package com.boya.factorymethod;
2.
3. public class Dog extends Animal {
4.
5. @Override
6. public void eat() {
7. System.out.println("狗吃肉");
8. }
9.
10. }
1. package com.boya.factorymethod;
2.
3. public interface Factory {
4. public Animal createAnimal();
5. }
1. package com.boya.factorymethod;
2.
3. public class CatFactory implements Factory {
4.
5. @Override
6. public Animal createAnimal() {
7.
8. return new Cat();
9. }
10.
11. }
1. package com.boya.factorymethod;
2.
3. public class DogFactory implements Factory {
4.
5. @Override
6. public Animal createAnimal() {
7.
8. return new Dog();
9. }
10.
11. }
1. package com.boya.factorymethod;
2.
3. public class Test {
4.
5. /**
6. * @param args
7. */
8. public static void main(String[] args) {
9. DogFactory df = new DogFactory();
10. Dog d = (Dog) df.createAnimal();
11. d.eat();
12. }
13.
14. }
3:多线程(多线程的引入)
- 1.什么是线程
- 线程是程序执行的一条路径, 一个进程中可以包含多条线程
- 多线程并发执行可以提高程序的效率, 可以同时完成多项工作
- 2.多线程的应用场景
- 红蜘蛛同时共享屏幕给多个电脑
- 迅雷开启多条线程一起下载
- QQ同时和多个人一起视频
- 服务器同时处理多个客户端请求
4:多线程(多线程并行和并发的区别)
-
并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
-
并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。
-
比如我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙聊天,这就叫并行。
-
如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再跟乙聊。这就叫并发。
5:多线程(Java程序运行原理和JVM的启动是多线程的吗)
-
A:Java程序运行原理
- Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。
-
B:JVM的启动是多线程的吗
- JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
案例(证明JVM是多线程的):
- JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
1. package com.boya.thread;
2.
3. public class Demo1_Thread {
4.
5. /**
6. * @param args
7. * 证明jvm是多线程的
8. */
9. public static void main(String[] args) {
10. for(int i = 0; i < 100000; i++) {
11. new Demo();
12. }
13.
14. for(int i = 0; i < 10000; i++) {
15. System.out.println("我是主线程的执行代码");
16. }
17. }
18.
19. }
20.
21. class Demo {
22.
23. @Override
24. public void finalize() {
25. System.out.println("垃圾被清扫了");
26. }
27. }
6:多线程(多线程程序实现的方式1)
- 1.继承Thread
- 定义类继承Thread
- 重写run方法
- 把新线程要做的事写在run方法中
- 创建线程对象
- 开启新线程, 内部会自动执行run方法
案例:
1. package com.boya.thread;
2.
3. public class Demo2_Thread {
4.
5. /**
6. * @param args
7. */
8. public static void main(String[] args) {
9. MyThread mt = new MyThread(); //4,创建Thread类的子类对象
10. mt.start(); //5,开启线程,调用run方法
11.
12. for(int i = 0; i < 1000; i++) {
13. System.out.println("bb");
14. }
15. }
16.
17. }
18.
19. class MyThread extends Thread { //1,继承Thread
20. public void run() { //2,重写run方法
21. for(int i = 0; i < 1000; i++) { //3,将要执行的代码写在run方法中
22. System.out.println("aaaaaaaaaaaa");
23. }
24. }
25. }
7:多线程(多线程程序实现的方式2)
- 2.实现Runnable
- 定义类实现Runnable接口
- 实现run方法
- 把新线程要做的事写在run方法中
- 创建自定义的Runnable的子类对象
- 创建Thread对象, 传入Runnable
- 调用start()开启新线程, 内部会自动调用Runnable的run()方法
案例:
1. package com.boya.thread;
2.
3. public class Demo3_Thread {
4.
5. /**
6. * @param args
7. */
8. public static void main(String[] args) {
9. MyRunnable mr = new MyRunnable(); //4,创建Runnable的子类对象
10. //Runnable target = mr; mr = 0x0011(地址值)
11. Thread t = new Thread(mr); //5,将其当作参数传递给Thread的构造函数
12. t.start(); //6,开启线程
13.
14. for(int i = 0; i < 1000; i++) {
15. System.out.println("bb");
16. }
17. }
18.
19. }
20.
21. class MyRunnable implements Runnable { //1,定义一个类实现Runnable
22.
23. @Override
24. public void run() { //2,重写run方法
25. for(int i = 0; i < 1000; i++) { //3,将要执行的代码写在run方法中
26. System.out.println("aaaaaaaaaaaa");
27. }
28. }
29.
30. }
8:多线程(实现Runnable的原理)
- 查看源码
- 1,看Thread类的构造函数,传递了Runnable接口的引用
- 2,通过init()方法找到传递的 target 给成员变量的 target 赋值
- 3,查看run方法,发现run方法中有判断,如果target不为null就会调用Runnable接口子类对象的run方法
9:多线程(两种方式的区别)
-
查看源码的区别:
- a.继承Thread : 由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
- b.实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()方法时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法
-
继承Thread
- 好处是:可以直接使用Thread类中的方法,代码简单
- 弊端是:如果已经有了父类,就不能用这种方法
-
实现Runnable接口
- 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
- 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂
10_多线程(匿名内部类实现线程的两种方式)
案例:
1. package com.boya.thread;
2.public class Demo4_Thread {
2.
3. /**
4. * @param args
5. */
6. public static void main(String[] args) {
7. //继承Thread类
8. new Thread() { //1,继承Thread类
9. public void run() { //2,重写run方法
10. for(int i = 0; i < 1000; i++) { //3,将要执行的代码写在run方法中
11. System.out.println("aaaaaaaaaaaaaa");
12. }
13. }
14. }.start(); //4,开启线程
15. //实现Runnable接口
16. new Thread(new Runnable() { //1,将Runnable的子类对象传递给Thread的构造方法
17. public void run() { //2,重写run方法
18. for(int i = 0; i < 1000; i++) { //3,将要执行的代码写在run方法中
19. System.out.println("bb");
20. }
21. }
22. }).start(); //4,开启线程
23. }
24.
25. }
11:多线程(获取名字和设置名字)
- 1.获取名字
- 通过getName()方法获取线程对象的名字
- 2.设置名字
- 通过构造函数可以传入String类型的名字
案例:
- 通过构造函数可以传入String类型的名字
1. package com.boya.threadmethod;
2.
3. public class Demo1_Name {
4.
5. /**
6. * @param args
7. */
8. public static void main(String[] args) {
9. //demo1();
10. //demo2();
11. demo3();
12. }
13.
14. public static void demo2() {
15. new Thread() {
16. public void run() {
17. this.setName("张三");
18. System.out.println(this.getName() + "....aaaaaaaaaaaaa");
19. }
20. }.start();
21. new Thread() {
22. public void run() {
23. this.setName("李四");
24. System.out.println(this.getName() + "....bb");
25. }
26. }.start();
27. }
28.
29. public static void demo3() {
30. Thread t1 = new Thread() {
31. public void run() {
32. //this.setName("张三");
33. System.out.println(this.getName() + "....aaaaaaaaaaaaa");
34. }
35. };
36.
37. Thread t2 = new Thread() {
38. public void run() {
39. //this.setName("李四");
40. System.out.println(this.getName() + "....bb");
41. }
42. };
43.
44. t1.setName("张三");
45. t2.setName("李四");
46. t1.start();
47. t2.start();
48. }
49.
50. public static void demo1() {
51. //this代表当前线程对象,在构造时不传线程名称,获取名称时显示为thread0,thread1,thread2.....
52. new Thread("芙蓉姐姐") { //通过构造方法给name赋值
53. public void run() {
54. System.out.println(this.getName() + "....aaaaaaaaa");
55. }
56. }.start();
57.
58. new Thread("凤姐") {
59. public void run() {
60. System.out.println(this.getName() + "....bb");
61. }
62. }.start();
63. }
64.
65. }
12:多线程(获取当前线程的对象)
- Thread.currentThread(), 主线程也可以获取
案例:
1. package com.boya.threadmethod;
2.
3. public class Demo2_CurrentThread {
4.
5. public static void main(String[] args) {
6. new Thread() {
7. public void run() {
8. System.out.println(getName() + "....aaaaaa");
9. }
10. }.start();
11.
12.
13. new Thread(new Runnable() {
14. public void run() {
15. //Thread.currentThread()获取当前正在执行的线程
16. System.out.println(Thread.currentThread().getName() + "...bb");
17. }
18. }).start();
19. //设置主线程的名字
20. Thread.currentThread().setName("我是主线程");
21. //直接写在main方法中,获取的是主线程
22. System.out.println(Thread.currentThread().getName());
23. }
24.
25. }
26.