首页 > 代码库 > javaSE第二十四天
javaSE第二十四天
第二十四天????363
1:多线程(理解)????363
(1)JDK5以后的Lock锁????363
A:定义????363
B:方法:????364
C:具体应用(以售票程序为例)????364
1,. SellTicket类????364
2,. SellTicketDemo测试类????365
(2)死锁问题的描述和代码体现????365
1. DieLockDemo测试类????365
2. DieLock类(该类继承自Thread)????366
3. MyLock(锁对象类)????367
(3)生产者和消费者多线程体现(线程间通信问题)????367
A:最基本的版本,只有一个数据。????367
1. Student资源类????367
2. SetThread(生产者类)????368
3. GetThread(消费者类)????368
4. StudentDemo测试类????369
B:改进版本,给出了不同的数据,并加入了同步机制????369
1. Student资源类????369
2. SetThread(生产者类)????370
3. GetThread(消费者)????370
4. StudentDemo(测试类)????371
C:等待唤醒机制改进该程序,让数据能够实现依次的出现????372
1. Student(资源类)????372
2. SetThread(生产者类)????373
3. GetThread(消费者类)????374
4. StudentDemo(测试类)????374
D:等待唤醒机制的代码优化。把数据及操作都写在了资源类中????376
1. Student(资源类,把数据及操作都写在资源类中)????376
2. SetThread(生产者类)????377
3. GetThread(消费者类)????378
4. StudentDemo(测试类)????378
(4)线程组????380
1. MyRunnable(线程类)????380
2. ThreadGroupDemo(测试类)????380
(5)线程池????382
1. MyRunnable(线程类)????382
2. ExecutorsDemo(线程池类)????382
(6)多线程实现的第三种方案????383
(7)匿名内部类方法实现多线程????386
(8)定时器的介绍????387
1. TimerDemo类(任务完成之后,可以终止定时器)????387
2. TimerDemo2类(任务完成之后,不终止定时器)????388
3. 案例:定时删除某个目录下的所有文件????389
(9)多线程的面试题????390
2:设计模式(理解)????391
(1)面试对象的常见设计原则????391
(2)设计模式概述和分类????391
(3)改进的设计模式????391
A:简单工厂模式????391
B:工厂方法模式????393
C:单例模式(掌握)????395
a:饿汉式:????395
b:懒汉式:????396
(4)Runtime????398
?
?
?
第二十四天
1:多线程(理解)
????(1)JDK5以后的Lock锁
????????A:定义
JDK5以后的针对线程的锁定操作和释放操作(Lock是一个接口,具体实例由其实现类ReentrantLock)
????????B:方法:
????????????实现类:ReenTrantlock的方法:
????????????void lock():加锁
????????????void unlock():解锁
????????C:具体应用(以售票程序为例)
????????????1,. SellTicket类
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; ? public?class SellTicket implements Runnable { ? ????// 定义票 ????private?int?tickets = 100; ? ????// 定义锁对象 ????private Lock lock = new ReentrantLock(); ? ????@Override ????public?void run() { ????????while (true) { ????????????try { ????????????????// 加锁 ????????????????lock.lock(); ????????????????if (tickets > 0) { ????????????????????try { ????????????????????????//为了模拟真实环境,对线程进行了延迟 ????????????????????????Thread.sleep(100); ????????????????????} catch (InterruptedException e) { ????????????????????????e.printStackTrace(); ????????????????????} ????????????????????System.out.println(Thread.currentThread().getName() ????????????????????????????+ "正在出售第" + (tickets--) + "张票"); ????????????????} ????????????} finally { ????????????????// 释放锁 ????????????????lock.unlock(); ????????????} ????????} ????} ? } |
?
?
????????????2,. SellTicketDemo测试类
/* * 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁, * 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。 * * Lock: * ????????void lock(): 获取锁。 * ????????void unlock():释放锁。 * ReentrantLock是Lock的实现类. * 通过ReentrantLock类来创建锁对象 */ public?class SellTicketDemo { ????public?static?void main(String[] args) { ????????// 创建资源对象 ????????SellTicket st = new SellTicket(); ? ????????// 创建三个窗口 ????????Thread t1 = new Thread(st, "窗口1"); ????????Thread t2 = new Thread(st, "窗口2"); ????????Thread t3 = new Thread(st, "窗口3"); ? ????????// 启动线程 ????????t1.start(); ????????t2.start(); ????????t3.start(); ????} } |
?
?
????(2)死锁问题的描述和代码体现
????????1. DieLockDemo测试类
/* * 同步的弊端: * ????????A:效率低 * ????????B:容易产生死锁 * * 死锁: * ????????两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。 * * 举例: * ????????中国人,美国人吃饭案例。 * ????????正常情况: * ????????????中国人:筷子两支 * ????????????美国人:刀和叉 * ????????现在: * ????????????中国人:筷子1支,刀一把 * ????????????美国人:筷子1支,叉一把 */ public?class DieLockDemo { ????public?static?void main(String[] args) { ????????DieLock dl1 = new DieLock(true); ????????DieLock dl2 = new DieLock(false); ? ????????dl1.start(); ????????dl2.start(); ????} } |
?
?
????????2. DieLock类(该类继承自Thread)
/** * 死锁演示 * @author asus1 * */ public?class DieLock extends Thread { ? ????private?boolean?flag; ? ????public DieLock(boolean?flag) { ????????this.flag = flag; ????} ? ????@Override ????public?void run() { ????????if (flag) { ????????????synchronized (MyLock.objA) { ????????????????System.out.println("if objA"); ????????????????synchronized (MyLock.objB) { ????????????????????System.out.println("if objB"); ????????????????} ????????????} ????????} else { ????????????synchronized (MyLock.objB) { ????????????????System.out.println("else objB"); ????????????????synchronized (MyLock.objA) { ????????????????????System.out.println("else objA"); ????????????????} ????????????} ????????} ????} } |
?
????????3. MyLock(锁对象类)
/** * 死锁演示 * @author asus1 * */ public?class MyLock { ????// 创建两把锁对象 ????public?static?final Object objA = new Object(); ????public?static?final Object objB = new Object(); } |
?
????(3)生产者和消费者多线程体现(线程间通信问题)
????????以学生作为资源来实现的
????????
????????资源类:Student
????????设置数据类:SetThread(生产者)
????????获取数据类:GetThread(消费者)
????????测试类:StudentDemo
????????
????????代码:
????????????A:最基本的版本,只有一个数据。
????????????????1. Student资源类
/* * Student:资源类 */ public?class Student { ????public String name; ????public?int?age; } |
?
????????????????2. SetThread(生产者类)
/* * 生产者类: */ public?class SetThread implements Runnable { ????//保证每个线程是对同一个对象进行操作 ????private Student s; ? ????public SetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????// Student s = new Student(); ????????s.name = "林青霞"; ????????s.age = 27; ????} } |
?
????????????????3. GetThread(消费者类)
/* * 消费者类 */ public?class GetThread implements Runnable { ????//保证每个线程是对同一个对象进行操作 ????private Student s; ? ????public GetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????// Student s = new Student(); ????????System.out.println(s.name + "---" + s.age); ????} } |
?
?
????????????????4. StudentDemo测试类
/* * 分析: * ????????资源类:Student???? * ????????设置学生数据:SetThread(生产者) * ????????获取学生数据:GetThread(消费者) * ????????测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null---0 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 * 如何实现呢? * ????????在外界把这个数据创建出来,通过构造方法传递给其他的类。 * */ public?class StudentDemo { ????public?static?void main(String[] args) { ????????//创建资源 ????????Student s = new Student(); ???????? ????????//设置和获取的类 ????????SetThread st = new SetThread(s); ????????GetThread gt = new GetThread(s); ? ????????//线程类 ????????Thread t1 = new Thread(st); ????????Thread t2 = new Thread(gt); ? ????????//启动线程 ????????t1.start(); ????????t2.start(); ????} } |
?
?
????????????B:改进版本,给出了不同的数据,并加入了同步机制
????????????????1. Student资源类
/* * 资源类: */ public?class Student { ????String name; ????int?age; } |
?
?
????????????????2. SetThread(生产者类)
/* * 生产者类: */ public?class SetThread implements Runnable { ? ????private Student s; ????private?int?x = 0; ? ????public SetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????while (true) { ????????????//加入了同步代码块,要保证多个线程是同意把锁 ????????????synchronized (s) { ????????????????if (x % 2 == 0) { ????????????????????s.name = "林青霞";//刚走到这里,就被别人抢到了执行权 ????????????????????s.age = 27; ????????????????} else { ????????????????????s.name = "刘意"; //刚走到这里,就被别人抢到了执行权 ????????????????????s.age = 30; ????????????????} ????????????????x++; ????????????} ????????} ????} } |
?
?
????????????????3. GetThread(消费者)
/* * 消费者类: */ public?class GetThread implements Runnable { ????private Student s; ? ????public GetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????while (true) { ????????????//加入了同步代码块 ????????????synchronized (s) { ????????????????System.out.println(s.name + "---" + s.age); ????????????} ????????} ????} } |
?
?
????????????????4. StudentDemo(测试类)
/* * 分析: * ????????资源类:Student???? * ????????设置学生数据:SetThread(生产者) * ????????获取学生数据:GetThread(消费者) * ????????测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null---0 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 * 如何实现呢? * ????????在外界把这个数据创建出来,通过构造方法传递给其他的类。 * * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题 * ????????A:同一个数据出现多次 * ????????B:姓名和年龄不匹配 * 原因: * ????????A:同一个数据出现多次 * ????????????CPU的一点点时间片的执行权,就足够你执行很多次。 * ????????B:姓名和年龄不匹配 * ????????????线程运行的随机性 * 线程安全问题: * ????????A:是否是多线程环境????????是 * ????????B:是否有共享数据????????是 * ????????C:是否有多条语句操作共享数据????是 * 解决方案: * ????????加锁。 * ????????注意: * ????????????A:不同种类的线程都要加锁。 * ????????????B:不同种类的线程加的锁必须是同一把。 */ public?class StudentDemo { ????public?static?void main(String[] args) { ????????//创建资源 ????????Student s = new Student(); ???????? ????????//设置和获取的类 ????????SetThread st = new SetThread(s); ????????GetThread gt = new GetThread(s); ? ????????//线程类 ????????Thread t1 = new Thread(st); ????????Thread t2 = new Thread(gt); ? ????????//启动线程 ????????t1.start(); ????????t2.start(); ????} } |
?
?
????????????C:等待唤醒机制改进该程序,让数据能够实现依次的出现
????????????????Object类的方法:
wait():让线程等待,并释放锁
????????????????notify():唤醒线程,并加锁
????????????????notifyAll() (多生产多消费)
????????????????1. Student(资源类)
/* * 资源类: */ public?class Student { ????String name; ????int?age; ????boolean?flag; // 默认情况是没有数据,如果是true,说明有数据 } |
?
?
????????????????2. SetThread(生产者类)
/* * 生产者类:加入了等待-唤醒机制 */ public?class SetThread implements Runnable { ? ????private Student s; ????private?int?x = 0; ? ????public SetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????while (true) { ????????????synchronized (s) { ????????????????//判断有没有 ????????????????if(s.flag){ ????????????????????try { ????????????????????????s.wait(); //t1等着,释放锁 ????????????????????} catch (InterruptedException e) { ????????????????????????e.printStackTrace(); ????????????????????} ????????????????} ???????????????? ????????????????if (x % 2 == 0) { ????????????????????s.name = "林青霞"; ????????????????????s.age = 27; ????????????????} else { ????????????????????s.name = "刘意"; ????????????????????s.age = 30; ????????????????} ????????????????x++; //x=1 ???????????????? ????????????????//修改标记 ????????????????s.flag = true; ????????????????//唤醒线程 ????????????????s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。 ????????????} ????????????//t1有,或者t2有 ????????} ????} } |
?
????????????????3. GetThread(消费者类)
/* * 消费者类:加入了等待-唤醒机制 */ public?class GetThread implements Runnable { ????private Student s; ? ????public GetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????while (true) { ????????????synchronized (s) { ????????????????if(!s.flag){ ????????????????????try { ????????????????????????s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候 ????????????????????} catch (InterruptedException e) { ????????????????????????e.printStackTrace(); ????????????????????} ????????????????} ???????????????? ????????????????System.out.println(s.name + "---" + s.age); ????????????????//林青霞---27 ????????????????//刘意---30 ???????????????? ????????????????//修改标记 ????????????????s.flag = false; ????????????????//唤醒线程 ????????????????s.notify(); //唤醒t1 ????????????} ????????} ????} } |
?
????????????????4. StudentDemo(测试类)
/* * 分析: * ????????资源类:Student???? * ????????设置学生数据:SetThread(生产者) * ????????获取学生数据:GetThread(消费者) * ????????测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null---0 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 * 如何实现呢? * ????????在外界把这个数据创建出来,通过构造方法传递给其他的类。 * * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题 * ????????A:同一个数据出现多次 * ????????B:姓名和年龄不匹配 * 原因: * ????????A:同一个数据出现多次 * ????????????CPU的一点点时间片的执行权,就足够你执行很多次。 * ????????B:姓名和年龄不匹配 * ????????????线程运行的随机性 * 线程安全问题: * ????????A:是否是多线程环境????????是 * ????????B:是否有共享数据????????是 * ????????C:是否有多条语句操作共享数据????是 * 解决方案: * ????????加锁。 * ????????注意: * ????????????A:不同种类的线程都要加锁。 * ????????????B:不同种类的线程加的锁必须是同一把。 * * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。 * 如何实现呢? * ????????通过Java提供的等待唤醒机制解决。 * * 等待唤醒: * ????????Object类中提供了三个方法: * ????????????wait():等待 * ????????????notify():唤醒单个线程 * ????????????notifyAll():唤醒所有线程 * ????????为什么这些方法不定义在Thread类中呢? * ????????????这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。 * ????????????所以,这些方法必须定义在Object类中。 */ public?class StudentDemo { ????public?static?void main(String[] args) { ????????//创建资源 ????????Student s = new Student(); ???????? ????????//设置和获取的类 ????????SetThread st = new SetThread(s); ????????GetThread gt = new GetThread(s); ? ????????//线程类 ????????Thread t1 = new Thread(st); ????????Thread t2 = new Thread(gt); ? ????????//启动线程 ????????t1.start(); ????????t2.start(); ????} } |
?
?
?
?
????????????D:等待唤醒机制的代码优化。把数据及操作都写在了资源类中
????????????1. Student(资源类,把数据及操作都写在资源类中)
/* * 资源类:把数据及操作都写在资源类上面 */ public?class Student { ????private String name; ????private?int?age; ????private?boolean?flag; // 默认情况是没有数据,如果是true,说明有数据 ? ????//使用同步方法解决线程安全问题 ????public?synchronized?void set(String name, int?age) { ????????// 如果有数据,就等待 ????????if (this.flag) { ????????????try { ????????????????this.wait(); ????????????} catch (InterruptedException e) { ????????????????e.printStackTrace(); ????????????} ????????} ? ????????// 设置数据 ????????this.name = name; ????????this.age = age; ? ????????// 修改标记 ????????this.flag = true; ????????this.notify(); ????} ? ????//使用同步方法解决线程安全问题 ????public?synchronized?void get() { ????????// 如果没有数据,就等待 ????????if (!this.flag) { ????????????try { ????????????????this.wait(); ????????????} catch (InterruptedException e) { ????????????????e.printStackTrace(); ????????????} ????????} ? ????????// 获取数据 ????????System.out.println(this.name + "---" + this.age); ? ????????// 修改标记 ????????this.flag = false; ????????this.notify(); ????} } |
?
?
????????????2. SetThread(生产者类)
/* * 生产者类: */ public?class SetThread implements Runnable { ? ????private Student s; ????private?int?x = 0; ? ????public SetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????while (true) { ????????????if (x % 2 == 0) { ????????????????s.set("林青霞", 27); ????????????} else { ????????????????s.set("刘意", 30); ????????????} ????????????x++; ????????} ????} } |
?
?
????????????3. GetThread(消费者类)
/* * 消费者类: */ public?class GetThread implements Runnable { ????private Student s; ? ????public GetThread(Student s) { ????????this.s = s; ????} ? ????@Override ????public?void run() { ????????while (true) { ????????????s.get(); ????????} ????} } |
?
?
????????????4. StudentDemo(测试类)
?
/* * 分析: * ????????资源类:Student???? * ????????设置学生数据:SetThread(生产者) * ????????获取学生数据:GetThread(消费者) * ????????测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null---0 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 * 如何实现呢? * ????????在外界把这个数据创建出来,通过构造方法传递给其他的类。 * * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题 * ????????A:同一个数据出现多次 * ????????B:姓名和年龄不匹配 * 原因: * ????????A:同一个数据出现多次 * ????????????CPU的一点点时间片的执行权,就足够你执行很多次。 * ????????B:姓名和年龄不匹配 * ????????????线程运行的随机性 * 线程安全问题: * ????????A:是否是多线程环境????????是 * ????????B:是否有共享数据????????是 * ????????C:是否有多条语句操作共享数据????是 * 解决方案: * ????????加锁。 * ????????注意: * ????????????A:不同种类的线程都要加锁。 * ????????????B:不同种类的线程加的锁必须是同一把。 * * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。 * 如何实现呢? * ????????通过Java提供的等待唤醒机制解决。 * * 等待唤醒: * ????????Object类中提供了三个方法: * ????????????wait():等待 * ????????????notify():唤醒单个线程 * ????????????notifyAll():唤醒所有线程 * ????????为什么这些方法不定义在Thread类中呢? * ????????????这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。 * ????????????所以,这些方法必须定义在Object类中。 * * 最终版代码中: * ????????把Student的成员变量给私有的了。 * ????????把设置和获取的操作给封装成了功能,并加了同步。 * ????????设置或者获取的线程里面只需要调用方法即可。 */ public?class StudentDemo { ????public?static?void main(String[] args) { ????????//创建资源 ????????Student s = new Student(); ???????? ????????//设置和获取的类 ????????SetThread st = new SetThread(s); ????????GetThread gt = new GetThread(s); ? ????????//线程类 ????????Thread t1 = new Thread(st); ????????Thread t2 = new Thread(gt); ? ????????//启动线程 ????????t1.start(); ????????t2.start(); ????} } |
?
?
?
?
?
????(4)线程组
????????具体案例介绍
????????????1. MyRunnable(线程类)
/* * 实现Runnable接口的线程类 */ public?class MyRunnable implements Runnable { ? ????@Override ????public?void run() { ????????for (int?x = 0; x < 100; x++) { ????????????//打印当前线程的名称及数字 ????????????System.out.println(Thread.currentThread().getName() + ":" + x); ????????} ????} ? } |
?
????????????2. ThreadGroupDemo(测试类)
/* * 线程组: 把多个线程组合到一起。 * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。 * * 线程组类:ThreadGroup * ????????构造方法:public ThreadGroup(String name):构造一个带名称的线程组 * ????????普通方法:public final String getName():返回此线程组的名称。 * ????注意:默认情况下,所有的线程都属于同一个组,就是main组 * Thread类: * ????????构造方法: * ????????public Thread(ThreadGroup group, Runnable target, String name):创建一个属于某个线程组的且带名称的线程 普通方法 public final ThreadGroup getThreadGroup():返回该线程所属的线程组 ? */ public?class ThreadGroupDemo { ????public?static?void main(String[] args) { ????????// method1(); ? ????????// 我们如何修改线程所在的组呢? ????????// 创建一个线程组 ????????// 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组 ????????method2(); ? ????????// t1.start(); ????????// t2.start(); ????} ? ????private?static?void method2() { ????????// ThreadGroup(String name) ????????ThreadGroup tg = new ThreadGroup("这是一个新的组"); ? ????????MyRunnable my = new MyRunnable(); ????????// Thread(ThreadGroup group, Runnable target, String name) ????????Thread t1 = new Thread(tg, my, "林青霞"); ????????Thread t2 = new Thread(tg, my, "刘意"); ???????? ????????System.out.println(t1.getThreadGroup().getName()); ????????System.out.println(t2.getThreadGroup().getName()); ???????? ????????//通过组名称设置后台线程,表示该组的线程都是后台线程 ????????tg.setDaemon(true); ????} ? ????private?static?void?method1() { ????????MyRunnable my = new MyRunnable(); ????????Thread t1 = new Thread(my, "林青霞"); ????????Thread t2 = new Thread(my, "刘意"); ????????// 我不知道他们属于那个线程组,我想知道,怎么办 ????????// 线程类里面的方法: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()); ????} } |
?
?
?
????(5)线程池
????????案例代码体现:
????????1. MyRunnable(线程类)
/* * 实现Runnable接口的线程类 */ public?class MyRunnable implements Runnable { ? ????@Override ????public?void run() { ????????for (int?x = 0; x < 100; x++) { ????????????//打印当前线程的名称及数字 ????????????System.out.println(Thread.currentThread().getName() + ":" + x); ????????} ????} ? } |
?
????????2. ExecutorsDemo(线程池类)
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; ? /* * 线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。 * * 如何实现线程的代码呢? * ????????A:创建一个线程池对象,控制要创建几个线程对象。 * ????????????public static ExecutorService newFixedThreadPool(int nThreads) * ????????B:这种线程池的线程可以执行: * ????????????可以执行Runnable对象或者Callable对象代表的线程 * ????????????做一个类实现Runnable接口。 * ????????C:调用如下方法即可 * ????????????Future<?> submit(Runnable task) *????????????<T> Future<T> submit(Callable<T> task) *????????D:我就要结束,可以吗? *????????????可以。 */ public?class ExecutorsDemo { ????public?static?void main(String[] args) { ????????// 创建一个线程池对象,控制要创建几个线程对象。 ????????// public static ExecutorService newFixedThreadPool(int nThreads) ????????ExecutorService pool = Executors.newFixedThreadPool(2); ? ????????// 可以执行Runnable对象或者Callable对象代表的线程 ????????pool.submit(new MyRunnable()); ????????pool.submit(new MyRunnable()); ? ????????//结束线程池 ????????pool.shutdown(); ????} } |
?
?
????(6)多线程实现的第三种方案
????????多线程实现第三种方式介绍:
????????1. MyCallable
import java.util.concurrent.Callable; ? //Callable:是带泛型的接口。 //这里指定的泛型其实是call()方法的返回值类型。 public?class MyCallable implements?Callable { ? ????@Override ????public Object call() throws Exception { ????????for (int?x = 0; x < 100; x++) { ????????????System.out.println(Thread.currentThread().getName() + ":" + x); ????????} ????????return?null; ????} ? } |
?
????????2. CallableDemo
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; ? /* * 多线程实现的方式3: * ????A:创建一个线程池对象,控制要创建几个线程对象。 * ????????????public static ExecutorService newFixedThreadPool(int nThreads) * ????????B:这种线程池的线程可以执行: * ????????????可以执行Runnable对象或者Callable对象代表的线程 * ????????????做一个类实现Runnable接口。 * ????????C:调用如下方法即可 * ????????????Future<?> submit(Runnable task) *????????????<T> Future<T> submit(Callable<T> task) *????????D:我就要结束,可以吗? *????????????可以。 */ public?class CallableDemo { ????public?static?void main(String[] args) { ????????//创建线程池对象 ????????ExecutorService pool = Executors.newFixedThreadPool(2); ???????? ????????//可以执行Runnable对象或者Callable对象代表的线程 ????????pool.submit(new MyCallable()); ????????pool.submit(new MyCallable()); ???????? ????????//结束 ????????pool.shutdown(); ????} } |
?
????????多线程案例:求和
????????1. MyCallable
import java.util.concurrent.Callable; ? /* * 线程求和案例 */ 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; ????} ? } |
?
????????2. CallableDemo
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import?java.util.concurrent.Executors; import java.util.concurrent.Future; ? /* * 多线程实现的方式3: * ????A:创建一个线程池对象,控制要创建几个线程对象。 * ????????????public static ExecutorService newFixedThreadPool(int nThreads) * ????????B:这种线程池的线程可以执行: * ????????????可以执行Runnable对象或者Callable对象代表的线程 * ????????????做一个类实现Runnable接口。 * ????????C:调用如下方法即可 * ????????????Future<?> submit(Runnable task) *????????????<T> Future<T> submit(Callable<T> task) *????????D:我就要结束,可以吗? *????????????可以。 */ public?class CallableDemo { ????public?static?void main(String[] args) throws InterruptedException, ExecutionException { ????????// 创建线程池对象 ????????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(); ????} } |
?
?
????(7)匿名内部类方法实现多线程
????
/* * 匿名内部类的格式: * ????????new 类名或者接口名() { * ????????????重写方法; * ????????}; * ????????本质:是该类或者接口的子类对象。 */ public?class ThreadDemo { ????public?static?void main(String[] args) { ????????// 继承Thread类来实现多线程 ????????new Thread() { ????????????public?void run() { ????????????????for (int?x = 0; x < 100; x++) { ????????????????????System.out.println(Thread.currentThread().getName() + ":" ????????????????????????????+ x); ????????????????} ????????????} ????????}.start(); ? ????????// 实现Runnable接口来实现多线程 ????????new Thread(new Runnable() { ????????????@Override ????????????public?void run() { ????????????????for (int?x = 0; x < 100; x++) { ????????????????????System.out.println(Thread.currentThread().getName() + ":" ????????????????????????????+ x); ????????????????} ????????????} ????????}) { ????????}.start(); ? ????????// 更有难度的,以下的这个代码是不会报错的,可以正常运行,需要能看懂 ????????new Thread(new Runnable() { ????????????@Override ????????????public?void run() { ????????????????for (int?x = 0; x < 100; x++) { ????????????????????System.out.println("hello" + ":" + x); ????????????????} ????????????} ????????}) { ????????????public?void run() { ????????????????for (int?x = 0; x < 100; x++) { ????????????????????System.out.println("world" + ":" + x); ????????????????} ????????????} ????????}.start(); ????} } |
?
????(8)定时器的介绍
????????1. TimerDemo类(任务完成之后,可以终止定时器)
import java.util.Timer; import java.util.TimerTask; ? /* * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。 * 依赖Timer和TimerTask这两个类: * Timer类:定时 * ????????public Timer() * ????????public void schedule(TimerTask task,long delay): * ????????????????????????????:安排在指定延迟后执行指定的任务。 * ????????public void schedule(TimerTask task, Date time) * ????????????????????????????:安排在指定的时间执行指定的任务 ? * ????????public void schedule(TimerTask task,long delay,long period) * ???????????????????????? :安排指定的任务在指定的时间开始进行重复的固定延迟执行。 * ????????public void cancel():终止此计时器,丢弃所有当前已安排的任务。 * ???????????????????????????? 这不会干扰当前正在执行的任务(如果存在)。 * TimerTask类:任务类 * ????????????子类继承该方法,并重写里面的run()方法 */ public?class TimerDemo { ????public?static?void main(String[] args) { ????????// 创建定时器对象 ????????Timer t = new Timer(); ????????// 3秒后执行爆炸任务 ????????// t.schedule(new MyTask(), 3000); ????????//结束任务 ????????t.schedule(new MyTask(t), 3000); ????} } ? // 做一个任务 class MyTask extends TimerTask { ? ????private Timer t; ???? ????public MyTask(){} ???? ????public MyTask(Timer t){ ????????this.t = t; ????} ????//要做的任务 ????@Override ????public?void run() { ????????System.out.println("beng,爆炸了"); ????????//任务执行完成之后,终止此定时器 ????????t.cancel(); ????} } |
?
????????2. TimerDemo2类(任务完成之后,不终止定时器)
import java.util.Timer; import java.util.TimerTask; ? /* * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。 * 依赖Timer和TimerTask这两个类: * Timer:定时 * ????????public Timer() * ????????public void schedule(TimerTask task,long delay) * ????????public void schedule(TimerTask task,long delay,long period) * ????????public void cancel() * TimerTask:任务 */ public?class TimerDemo2 { ????public?static?void main(String[] args) { ????????// 创建定时器对象 ????????Timer t = new Timer(); ????????// 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸 ????????t.schedule(new MyTask2(), 3000, 2000); ????????//该程序不会自动停止 ????} } ? // 做一个任务 class MyTask2 extends TimerTask { ????@Override ????public?void run() { ????????System.out.println("beng,爆炸了"); ????} } |
?
????????3. 案例:定时删除某个目录下的所有文件
import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; ? /* * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo) */ ? class DeleteFolder extends TimerTask { ? ????//定时任务 ????@Override ????public?void run() { ????????File srcFolder = new File("demo"); ????????deleteFolder(srcFolder); ????} ? ????// 递归删除目录 ????public?void deleteFolder(File srcFolder) { ????????//获取源目录下的所有File对象的数组 ????????File[] fileArray = srcFolder.listFiles(); ???????? ????????//判断该File数组是否为null ????????if (fileArray != null) { ????????????//不为null,循环遍历 该数组 ????????????for (File file : fileArray) { ???????????????? ????????????????//判断该file对象是否为目录 ????????????????if (file.isDirectory()) { ????????????????????//如果为目录,则进行递归 ????????????????????deleteFolder(file); ????????????????} else { ????????????????????//不为目录,则打印被删除文件的名称并同时删除文件 ????????????????????System.out.println(file.getName() + ":" + file.delete()); ????????????????} ????????????} ????????????//如果File数组为null,则打印被删除文件的名称并同时删除文件 ????????????System.out.println(srcFolder.getName() + ":" + srcFolder.delete()); ????????} ????} } ? //测试类 public?class TimerTest { ????public?static?void main(String[] args) throws ParseException { ????????//创建定时器对象 ????????Timer t = new Timer(); ? ????????String s = "2014-11-27 15:45:00"; ????????SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ????????Date d = sdf.parse(s); ????????//在指定的时间,删除某个目录下的所有文件 ????????t.schedule(new DeleteFolder(), d); ????} } |
?
?
????(9)多线程的面试题
1:多线程有几种实现方案,分别是哪几种? ????两种。 ???? ????继承Thread类 ????实现Runnable接口 ???? ????扩展一种:实现Callable接口。这个得和线程池结合。 ? 2:同步有几种方式,分别是什么? ????两种。 ???? ????同步代码块 ????同步方法 ? 3:启动一个线程是run()还是start()?它们的区别? ????start(); ???? ????run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用 ????start():启动线程,并由JVM自动调用run()方法 ? 4:sleep()和wait()方法的区别 ????sleep():必须指时间;不释放锁。 ????wait():可以不指定时间,也可以指定时间;释放锁。 ? 5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中 ????因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。 ????而Object代表任意的对象,所以,定义在这里面。 ? 6:线程的生命周期图 ????新建 -- 就绪 -- 运行 -- 死亡 ????新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡 ????建议:画图解释。 |
?
?
2:设计模式(理解)
????(1)面试对象的常见设计原则
????????单一
????????开闭
????????里氏
????????依赖注入
????????接口
????????迪米特
????(2)设计模式概述和分类
????????A:经验的总结
????????B:三类
????????????创建型
????????????结构型
????????????行为型
????(3)改进的设计模式
????????A:简单工厂模式
????????????1. Animal类(顶层抽象类)
/* * 动物类:抽象类 */ public?abstract?class Animal { ????//吃的方法 ????public?abstract?void eat(); } |
?
????????????2. Cat类
/* * 猫类:继承动物类 */ public?class Cat extends Animal { ????@Override ????public?void eat() { ????????System.out.println("猫吃鱼"); ????} ? } |
?
????????????3. Dog类
/* * 狗类:继承动物类 */ public?class Dog extends Animal { ? ????@Override ????public?void eat() { ????????System.out.println("狗吃肉"); ????} } |
?
????????????4. AnimalFactory类(动物工厂类)
????????????
/* * 动物工厂类:专门造动物的 */ public?class AnimalFactory { ????//构造方法私有,不允许创建对象 ????private AnimalFactory() { ????} ????//根据传递过来的类型,创建指定的对象,可通过类名直接调用 ????public?static Animal createAnimal(String type) { ????????if ("dog".equals(type)) { ????????????return?new Dog(); ????????} else?if ("cat".equals(type)) { ????????????return?new?Cat(); ????????} else { ????????????return?null; ????????} ????} } |
?
????????????5. AnimalDemo(测试类)
/* * 测试类 */ public?class AnimalDemo { ????public?static?void main(String[] args) { ????????// 具体类调用 ????????Dog d = new Dog(); ????????d.eat(); ????????Cat c = new Cat(); ????????c.eat(); ????????System.out.println("------------"); ? ????????// 工厂改进后 ????????Animal a = AnimalFactory.createAnimal("dog"); ????????a.eat(); ????????a = AnimalFactory.createAnimal("cat"); ????????a.eat(); ? ????????// NullPointerException,在使用对象之前,应该先对对象是否为null进行判断 ????????a = AnimalFactory.createAnimal("pig"); ????????if (a != null) { ????????????a.eat(); ????????} else { ????????????System.out.println("对不起,暂时不提供这种动物"); ????????} ????} } |
?
????????????
????????B:工厂方法模式
????????????1. Animal(动物类)
/* * 动物类:抽象 类 */ public?abstract?class Animal { ????public?abstract?void eat(); } |
?
????????????2. Cat类(猫类)
/* * 猫类:继承自动物类 */ public?class Cat extends Animal { ? ????@Override ????public?void eat() { ????????System.out.println("猫吃鱼"); ????} ? } |
?
????????????3. Dog(狗类)
/* * 狗类:继承自动物类 */ public?class Dog extends Animal { ? ????@Override ????public?void eat() { ????????System.out.println("狗吃肉"); ????} ? } |
?
????????????4. Factory(接口)
/* * Factory:工厂接口 */ public?interface Factory { ????//定义了创建动物的方法 ????public?abstract Animal createAnimal(); } |
?
????????????5. CatFactory(猫工厂)
/* * CatFactory:猫工厂,实现工厂接口,专门用来生成猫 */ public?class CatFactory implements Factory { ? ????@Override ????public Animal createAnimal() { ????????return?new Cat(); ????} ? } |
?
????????????6. DogFactory(狗工厂)
/* * 狗工厂:实现了工厂接口,专门用来造狗 */ public?class DogFactory implements Factory { ? ????@Override ????public Animal createAnimal() { ????????return?new Dog(); ????} ? } |
?
????????????7. AnimalDemo测试类
/* * 测试类 */ public?class AnimalDemo { ????public?static?void main(String[] args) { ????????// 需求:我要买只狗 ????????Factory f = new DogFactory(); ????????Animal a = f.createAnimal(); ????????a.eat(); ????????System.out.println("-------"); ???????? ????????//需求:我要买只猫 ????????f = new CatFactory(); ????????//使用特定的工厂专门造狗,造猫 ????????a = f.createAnimal(); ????????a.eat(); ????} } |
?
????????C:单例模式(掌握)
????????????a:饿汉式:
????????????说明:饿汉式:提前造好一个对象(开发中常用,因为不容易出现问题)
????????????1.
/* * 单例模式:饿汉式:提前造好一个对象 */ public?class Student { ????// 构造私有 ????private Student() { ????} ? ????// 自己造一个 ????// 静态方法只能访问静态成员变量,加静态 ????// 为了不让外界直接访问修改这个值,加private ????private?static Student s = new Student(); ? ????// 提供公共的访问方式 ????// 为了保证外界能够直接使用该方法,加静态 ????public?static Student getStudent() { ????????return?s; ????} } |
?
?
????????????2. StudentDemo测试类
/* * 单例模式:保证类在内存中只有一个对象。 * * 如何保证类在内存中只有一个对象呢? * ????????A:把构造方法私有 * ????????B:在成员位置自己创建一个对象 * ????????C:通过一个公共的方法提供访问 */ public?class StudentDemo { ????public?static?void main(String[] args) { ????????//通过单例模式得到对象 ????????Student s1 = Student.getStudent(); ????????Student s2 = Student.getStudent(); ????????System.out.println(s1 == s2); ? ????????System.out.println(s1); // null,cn.itcast_03.Student@175078b ????????System.out.println(s2);// null,cn.itcast_03.Student@175078b ????} } |
?
?
????????????b:懒汉式:
????????????说明:需要用的时候,才去创建对象。(面试常面)
????????????1. Teacher类
/* * 单例模式: * ????????饿汉式:类一加载就创建对象 * ????????懒汉式:用的时候,才去创建对象 * * 面试题:单例模式的思想是什么?请写一个代码体现。 * * ????????开发:饿汉式(是不会出问题的单例模式) * ????????面试:懒汉式(可能会出问题的单例模式) * ????????????A:懒加载(延迟加载)???? * ????????????B:线程安全问题 * ????????????????a:是否多线程环境????是 * ????????????????b:是否有共享数据????是 * ????????????????c:是否有多条语句操作共享数据 ????是 */ public?class Teacher { ????//构造方法私有化 ????private Teacher() { ????} ? ????//定义一个对象 ????private?static Teacher t = null; ? ????//加入同步关键字解决线程安全问题 ????public?synchronized?static Teacher getTeacher() { ????????// t1,t2,t3 ????????//如果对象为null,就创建,否则不创建 ????????if (t == null) { ????????????//t1,t2,t3 ????????????t = new Teacher(); ????????} ????????return?t; ????} } |
?
?
????????????2. TeacherDemo类
/* * 测试类 */ public?class TeacherDemo { ????public?static?void main(String[] args) { ????????Teacher t1 = Teacher.getTeacher(); ????????Teacher t2 = Teacher.getTeacher(); ????????System.out.println(t1 == t2); ????????System.out.println(t1); // cn.itcast_03.Teacher@175078b ????????System.out.println(t2);// cn.itcast_03.Teacher@175078b ????} } |
?
?
?
????(4)Runtime
????????JDK提供的一个单例模式应用的类。
????????还可以调用dos命令。
????????
import java.io.IOException; ? /* * Runtime:每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。 * exec(String command) */ public?class RuntimeDemo { ????public?static?void main(String[] args) throws IOException { ????????Runtime r = Runtime.getRuntime(); //????????r.exec("winmine"); ????????//打开记事本 ????????// r.exec("notepad"); ????????//打开计算器 ????????// r.exec("calc"); ????????//关机(时间是以秒计算的) //????????r.exec("shutdown -s -t 10000"); ????????//取消shutdown的命令 ????????r.exec("shutdown -a"); ????} } ? /*该Runtime类使用了单例模式 * class Runtime { * ????????private Runtime() {} * ????????private static Runtime currentRuntime = new Runtime(); * ????????public static Runtime getRuntime() { * ????return currentRuntime; * ????} * } */ |
?
?
javaSE第二十四天