java review
一、多态
- 向上转型
- FU fu = new Zi();
- 可以调用子类方法,不能调用子类特有方法 (成员方法)
- 成员变量,看等号左边的是谁,调用谁里面的成员变量
二、内部类
1.什么时候使用内部类:
当一个事务的内部,还有一个部分需要定义完整的结构去描述,而这个内部的完整结构又只为外部事物提供服务。那么整个内部的完整结构最好使用内部类
2.分类:
成员内部类(静态、非静态)
局部内部类
匿名内部类
1.静态内部类
1.格式:直接在定义内部类的时候加上static关键字
public class A {
static class B {
}
}
2.注意:
a.内部类可以定义属性,方法,构造等
b.静态内部类可以用final或者abstract修饰
被final 修饰后不能被继承
被abstract 修饰后不能new
c.静态内部类不能调用外部的非静态成员
d.内部类还可以被四种权限修饰符修饰
e.调用静态内部类成员
外部类.内部类 对象名 = new 外部类.内部类();
2.非静态内部类
1.格式:
public class A {
class B {
}
}
2.注意:
a.内部类可以定义属性,方法,构造等
b.静态内部类可以用final或者abstract修饰
被final 修饰后不能被继承
被abstract 修饰后不能new
c.静态内部类不能调用外部的非静态成员
d.内部类还可以被四种权限修饰符修饰
e.调用静态内部类成员
外部类.内部类 对象名 = new 外部类().new 内部类();
外部的成员变量和内部类的成员变量以及内部类的局部变量重名时怎么办?
public class Person { String name = "杨晨旭"; class Heart{ String name = "赵国羽"; public void display(String name){ System.out.println(name);//内部类的局部变量 System.out.println(this.name); //内部类的成员变量 System.out.println(Person.this.name); //外部类的成员变量 } } }
3.局部内部类
1.可以定义在方法中,代码块中,构造中
public class Person { public void eat(){ class Heart{ public void jump(){ System.out.println("心脏怦怦跳"); } } new Heart().jump(); } } public class Test01 { public static void main(String[] args) { Person person = new Person(); person.eat(); } }
3.1局部内部类实际操作
3.1.1接口类型作为方法参数传递和返回值
public interface Usb {
abstract void open();
}
public class Compute implements Usb{
@Override
public void open() {
System.out.println("compute is openning");
}
}
public class Test01 {
public static void main(String[] args) {
Compute compute = new Compute();
method(compute);
Usb usb = method01();
usb.open();
}
public static void method(Usb usb) {
usb.open();
}
public static Usb method01(){
return new Compute();
}
}
3.1.2抽象类作为方法参数传递和返回值
1.抽象类作为方法参数传递,传递的是其子类对象
2.抽象类作为方法返回值类型返回时,实际返回的是其子类对象
3.1.3普通类做方法参数和返回值
普通类作为方法参数传递,传递的是对象
普通类作为方法返回值返回,返回的是对象
3.1.4局部内部类实际操作
public interface Usb {
void open();
}
public class Test01 {
public static void main(String[] args) {
Usb usb = method01();
usb.open();
}
public static Usb method01(){
//局部内部类
class Compute implements Usb{
@Override
public void open() {
System.out.println("电脑打开了");
}
}
return new Compute();
}
}
4.匿名内部类
可以理解为没有显式的声明出类名的内部类
格式:
new 接口/抽象类(){
重写方法
}.重写的方法();
类名 对象名 = new 接口/抽象类(){
重写方法
}
对象名.重写的方法
public interface Usb {
void open();
}
public class Test01 {
public static void main(String[] args) {
new Usb(){
@Override
public void open() {
System.out.println("xaioguo");
}
}.open();
}
}
Object中的clone方法
1.作用:复制一个属性值一样的新对象
2.使用:
需要被克隆的对象实现Cloneable
重写clone方法
三、经典接口
1.java.lang.Comparable
- 哪个类的对象要比较大小,哪个类就实现java.lang.Comparable接口,并重写方法
- 方法体就是你要如何比较当前对象和指定的另一个对象的大小
- 对象比较大小时,通过对象调用compare To方法,根据方法的返回值决定谁大谁小
- this对象(调用compareTo方法的对象) 减 指定对象 (传入compareTo()的参数对象)大于0,返回正整数
- this对象(调用compareTo方法的对象) 减 指定对象 (传入compareTo()的参数对象)小于0,返回负整数
- this对象(调用compareTo方法的对象) 减 指定对象 (传入compareTo()的参数对象)等于0,返回零
2.java.util.Comparator
(1)如果一个类,没有实现Comparable接口,而这个类又不方便修改。(例如一些第三方的类,只有class类,没有源文件)
(2)如果一个类,实现了Comparable接口,也指定了两个对象的比较大小的规则,但是不小按照它预定义的方法比较大小,但是又不可以随意修改,因为会影响其他地方的使用。
package java.util
public interface Comparator{
int compare(Object o1,Object o2);
}
- 编写一个类,比较器类型,实现java.util.Comparator接口,并重写方法
- 方法体就是你要如何指定的两个对象的大小
- 比较大小时,通过比较器类型的对象调用compare()方法,将要比较大小的两个对象作为compare方法的实参传入
四、多线程
1.会使用多线程方法,主要是start方法
2.会使用继承Thread的方式创建多线程
3.会使用Runnable接口的方式实现多线程
4.会使用同步代码块,解决线程不安全问题
5.会使用同步方法,解决线程不安全问题
多线程的基本了解
1.多线程_线程和进程
进程:在内存中执行的应用程序
线程:是进程中的最小执行单元
线程作用:负责当前进程中程序的执行,一个进程中至少有一个线程,一个进进程还可以有多个线程,这样的应用程序就称之为多线程程序。
简单理解: 一个功能,需要一个线程
使用场景:软件中的耗时操作-->拷贝大文件,加载大量的资源
所有的聊天软件 、所有的后台服务器。
一个线程可以干一件事,同时做多件事,提高CPU利用率
2.并发和并行
并行:在同一个时刻,有多个执行在多个CPU上同时执行
并发:在同一个时刻,有多个指令在单个CPU上(交替)执行。
1.之前cpu是单核,但是在执行多个程序的时候好像是在同时执行,原因是CPU在多个线程之间做高速切换
2.现在cpu多核多线程,例如2核4线程,cpu可以同时运行4个线程,此时不同切换,但是如果多了,cpu就要i耳环了,所以现在cpu在执行程序的时候并发和并行同时存在。
3.cpu调度
1.分时调度:指的是让所有的线程轮流获取cpu使用权,并且平均分配每个线程占用cpu的时间片
2.抢占式调度:多个线程轮流抢占cpu的使用权,哪个线程先抢到了,哪个线程线执行,一般都是优先级高的抢到cpu使用权的几率大,java程序就是抢占式调用的。
4.主线程
cpu和内存之间开辟的专门为main方法服务的线程,称为主线程
创建线程的方式
第一种方式 extends Thread
1.定义一个类,继承Thread类
2.重写run方法,在run方法中设置线程任务(所谓的线程任务指的是此线程要干的具体的事儿,具体执行的代码)
3.创建自定义线程类的对象
4.调用Thread中的start方法,开启线程,jvm自动调用run方法
1.多线程在内存中的运行原理
开启一个线程,会开启一个栈空间去运行对应的线程代码,
注意: 同一个线程对象不能连续调用多次start方法。
2.Tread类中的方法
void start() -->开启线程,jvm自动调用run方法
void run() -->设置线程任务,这个run方法是Thread重写的接口Runnable中的run方法
String getName() --> 获取线程名字
void setName(String name) --> 给线程设置名字
static Thread currentThread() -->获取正在执行的线程对象(该方法在哪个线程对象中使用,获取的就是哪个线程对象)
static void sleep(long millis) --> 线程睡眠,超时后会自动醒来,传递的是毫秒值。
3.Thread中的其他方法
void setPriority(int newPriority) -->设置线程优先级,优先级越高,抢到CPU使用权的几率越大,但不是每次都先抢到
int getPriority() -->获取线程优先级
void setDaemon(boolean on) -->设置为守护线程,当非守护线程执行完毕,守护线程就要结束
static void yield() ——>礼让线程,让当前线程让出CPU使用权
void join() -->插入线程、插队线程
守护线程
package d_thread;
public class MyThread extends Thread{
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "...执行了" + i);
}
}
}
package d_thread;
public class MyThread2 extends Thread{
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "...执行了" + i);
}
}
}
package d_thread;
public class Test01 extends Thread{
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.setName("杨旭");
MyThread2 t2 = new MyThread2();
t2.setName("马宏");
t2.setDaemon(true);
t1.start();
t2.start();
}
}
--
马宏...执行了0
马宏...执行了1
杨旭...执行了0
杨旭...执行了1
杨旭...执行了2
马宏...执行了2
马宏...执行了3
杨旭...执行了3
杨旭...执行了4
杨旭...执行了5
杨旭...执行了6
杨旭...执行了7
杨旭...执行了8
马宏...执行了4
杨旭...执行了9
马宏...执行了5
马宏...执行了6
马宏...执行了7
马宏...执行了8
马宏...执行了9
马宏...执行了10
马宏...执行了11
马宏...执行了12
---
礼让线程
场景:如果两个线程一起执行,可能会执行一会线程A,在执行一会线程B,或者可能线程A执行完毕了,线程B再执行,那么我们能不能让两个线程尽可能的平衡一点 —>尽量让两个线程交替执行。
插入线程
public class Test01 extends Thread{
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
t1.setName("杨旭");
t1.start();
t1.join();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "...执行了" + i);
}
}
}
public class MyThread extends Thread{
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "...执行了" + i);
}
}
}
第二种方式
1.创建类,实现Runnable接口
2.重写run方法,设置线程任务
3.利用Thread类的构造方法: Thread(Runnable target),创建Thread对象(线程对象),将自定义的类当参数传递到Thread构造中 --> 这一步是让我们自己定义的类成为一个真正的线程类对象。
4.调用Thread中start方法,开启线程,jvm自动调用run方法。
两种实现多线程的方式区别
1.继承Thread:继承只支持单继承,有继承的局限性
2.实现Runnable:没有继承的局限性,MyThread extends Fu implements Runnable
第三种方式_匿名内部类创建多线程
严格意义上来说:匿名内部类方式部署于创建多线程方式其中之一,因为匿名内部类形式建立在实现Runnable接口的基础上完成的
匿名内部类 :
1.new 接口/抽象类(){
重写方法
}.重写的方法();
2.接口名/类名 对象名 =new 接口/抽象类(){
重写方法
}
对象名.重写的方法
public class Test02 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "...执行了" + i + "次");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "...执行了" + i + "次");
}
}
},"yangxu").start();
}
线程安全问题
1.线程安全问题--> 线程不安全的代码
原因: Cpu在多个线程之间做高速切换导致的
public class MyTicket implements Runnable{
//定义100张票
int ticket =100;
@Override
public void run() {
while (true){
if (ticket > 0){
System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
ticket --;
}
}
}
}
public class Test01 {
public static void main(String[] args) {
MyTicket myTicket = new MyTicket();
Thread t1 = new Thread(myTicket, "杨旭");
Thread t2 = new Thread(myTicket, "马洪");
Thread t3 = new Thread(myTicket, "赵桑");
t1.start();
t2.start();
t3.start();
}
}
2.解决线程安全问题的第一种方式(使用同步代码块)
1.格式:
synchronized(任意对象){
线程可能出现不安全的代码
}
2. 任意对象: 就是我们的锁对象
3. 执行:
一个线程拿到锁之后会进入到同步代码块中执行,在此期间,其他线程拿不到锁,就进不去同步代码块,需要在同步代码块外面等待排队,
需要等着执行的线程执行完毕,出了同步代码块,相当于释放锁,等待的线程才能抢到锁,才能进入到同步代码块中执行。
public class MyTicket implements Runnable{
Object obj = new Object();
//定义100张票
int ticket =100;
@Override
public void run() {
while (true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (obj){
if (ticket > 0){
System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
ticket --;
}
}
}
}
}
public class Test01 {
public static void main(String[] args) {
MyTicket myTicket = new MyTicket();
Thread t1 = new Thread(myTicket, "杨旭");
Thread t2 = new Thread(myTicket, "马洪");
Thread t3 = new Thread(myTicket, "赵桑");
t1.start();
t2.start();
t3.start();
}
}
3.解决线程安全问题的第二种方式:同步方法
3.1普通同步法:非静态
1. 格式:
修饰符 synchronized 返回值类型 方法名(参数){
方法体
return 结果
}
2. 默认锁是this
public class MyTicket implements Runnable {
//定义100张票
int ticket = 100;
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// method01();
method02();
}
}
// public synchronized void method01() {
// if (ticket > 0) {
// System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
// ticket--;
// }
// }
public void method02() {
synchronized (this){
System.out.println(this+ "......");
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
ticket--;
}
}
}
}
public class Test01 {
public static void main(String[] args) {
MyTicket myTicket = new MyTicket();
System.out.println(myTicket);
Thread t1 = new Thread(myTicket, "杨旭");
Thread t2 = new Thread(myTicket, "马洪");
Thread t3 = new Thread(myTicket, "赵桑");
t1.start();
t2.start();
t3.start();
}
}
3.2静态同步方法
1. 格式:
修饰符 static synchronized 返回值类型 方法名(参数){
方法体
return 结果
}
2.默认锁 class对象
public class MyTicket implements Runnable {
//定义100张票
static int ticket = 100;
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// method01();
method02();
}
}
// public static synchronized void method01() {
// if (ticket > 0) {
// System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
// ticket--;
// }
// }
public void method02() {
synchronized (MyTicket.class){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
ticket--;
}
}
}
}
public class Test01 {
public static void main(String[] args) {
MyTicket myTicket = new MyTicket();
System.out.println(myTicket);
Thread t1 = new Thread(myTicket, "杨旭");
Thread t2 = new Thread(myTicket, "马洪");
Thread t3 = new Thread(myTicket, "赵桑");
t1.start();
t2.start();
t3.start();
}
}
死锁
1.死锁介绍(锁嵌套就有可能产生死锁)
指的是两个或两个以上的线程在执行的过程中由于竞争同步锁而产生的一种阻塞现象;
如果没有外力的作用,它们将无法继续执行下去,这种情况称之为死锁。
线程1持有锁1,线程2持有锁2,线程1必须再拿到锁2才能继续执行,
线程2必须再拿到锁1才能继续执行,此时两个线程处于互相等待的状态,
在程序中的死锁将出现在同步代码块的嵌套中
public class LockA {
public static LockA lockA = new LockA();
}
public class LockB {
public static LockB lockB = new LockB();
}
public class DieLock implements Runnable {
private Boolean flag;
public DieLock(Boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
synchronized (LockA.lockA) {
System.out.println("if ....lockA");
synchronized (LockB.lockB) {
System.out.println("if ...lockB");
}
}
} else {
synchronized (LockB.lockB) {
System.out.println("else ....lockB");
synchronized (LockA.lockA) {
System.out.println("else ...lockA");
}
}
}
}
}
public class Test01 {
public static void main(String[] args) {
DieLock dieLock1 = new DieLock(true);
DieLock dieLock2 = new DieLock(false);
new Thread(dieLock1).start();
new Thread(dieLock2).start();
}
}
//也有可能不出现死锁
if ....lockA
if ...lockB
else ....lockB
else ...lockA
多线程_等待唤醒案例
package wait_notify;
public class BaoziPu {
private int count;
private boolean flag;
public BaoziPu() {
}
public void getCount() {
System.out.println("消费了"+ "第"+count + "包子");
}
public void setCount() {
count++;
System.out.println("生产了.....第" + count+"包子");
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public BaoziPu(int count, boolean flag) {
this.count = count;
this.flag = flag;
}
}
package wait_notify;
public class Product implements Runnable{
private BaoziPu baoziPu;
public Product(BaoziPu baoziPu) {
this.baoziPu = baoziPu;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (baoziPu){
if(baoziPu.isFlag() == true){
try {
baoziPu.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
baoziPu.setCount();
baoziPu.setFlag(true);
baoziPu.notify();
}
}
}
}
package wait_notify;
public class Comsumer implements Runnable{
private BaoziPu baoziPu;
public Comsumer(BaoziPu baoziPu) {
this.baoziPu = baoziPu;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (baoziPu){
if(baoziPu.isFlag() == false){
try {
baoziPu.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
baoziPu.getCount();
baoziPu.setFlag(false);
baoziPu.notify();
}
}
}
}
public class Test {
public static void main(String[] args) {
BaoziPu baoziPu = new BaoziPu();
Product product = new Product(baoziPu);
Comsumer comsumer = new Comsumer(baoziPu);
Thread t1 = new Thread(product);
Thread t2 = new Thread(comsumer);
t1.start();
t2.start();
}
}
代码改进
public synchronized void getCount() {
while (true) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (this.isFlag() == false) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("消费了" + "第" + count + "包子");
this.setFlag(false);
this.notify();
}
}
public synchronized void setCount() {
while (true) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (this.isFlag() == true) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
count++;
System.out.println("生产了.....第" + count + "包子");
this.setFlag(true);
this.notify();
}
}
public void run() {
baoziPu.setCount();
}
public void run() {
baoziPu.getCount();
}
多等待,多唤醒
while 和notifyAll() 搭配使用
new Thread(product).start();
new Thread(product).start();
new Thread(product).start();
new Thread(comsumer).start();
new Thread(comsumer).start();
new Thread(comsumer).start();
public synchronized void getCount() {
while (true) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
while (this.isFlag() == false) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("消费了" + "第" + count + "包子");
this.setFlag(false);
this.notifyAll();
}
}
public synchronized void setCount() {
while (true) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
while (this.isFlag() == true) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
count++;
System.out.println("生产了.....第" + count + "包子");
this.setFlag(true);
this.notifyAll();
}
}
多线程_Lock锁
1.Lock对象的介绍和使用
1.概述: Lock对象的介绍和基本使用
2.实现类: ReentrantLock
3.方法:
lock() 获取锁
unlock() 释放锁
解决线程不安全
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyTicket implements Runnable {
Lock lock = new ReentrantLock();
//定义100张票
int ticket = 100;
@Override
public void run() {
while (true) {
try {
Thread.sleep(100L);
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
ticket--;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}
}
MyTicket myTicket = new MyTicket();
Thread t1 = new Thread(myTicket, "杨旭");
Thread t2 = new Thread(myTicket, "马洪");
Thread t3 = new Thread(myTicket, "赵桑");
t1.start();
t2.start();
t3.start();
synchronized:不管是同步代码块还是同步方法,都需要在结束一对{}之后,释放对象
Lock:是通过两个方法控制需要被同步的代码,更灵活。
Callable接口(实现多线程的第三种方式)
1.概述:Callable
是一个接口,类似于Runnable 2.方法:
V call() -> 设置线程任务的,类似于run方法
3.call 方法和run方法的区别:
a.相同点:都是设置线程任务的
b.不同点:call方法有返回值,有异常可以throws
run方法没有返回值,有异常不可以throws
4.
a.
泛型 b. 泛型:用于指定我们操作什么类型的数据,<>中只能写引用数据类型,如果泛型不写默认是Object类型数据
c.实现Callable接口时,指定泛型是什么类型的,重写的call方法返回值就是什么类型的。
5.获取call方法的返回值:FuntureTask
a.FuntureTask
实现了一个接口 Future b.FuntureTask
中有一个方法: V get() 获取call方法的返回值
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "小liu";
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
/*
FutureTask(Callable<V> callable)
*/
FutureTask<String> myFutureTask = new FutureTask<>(myCallable);
Thread t1 = new Thread(myFutureTask);
t1.start();
System.out.println(myFutureTask.get());
}
}
线程池
1.问题:之前来一个线程任务,就需要创建一个线程对象去执行,用完还要销毁线程对象,如果线程任务多了,就需要频繁创建线程对象,销毁线程对象,耗费资源,线程对象能不能循环使用,用的时候直接拿,用完还回来。
1.如何创建线程池对象: 工具类 —> Executors
2.获取线程池对象:Executors中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads)
a.参数:指定线程池中最多创建的线程对象条数
b.返回值ExecutorService 是线程池,用来管理线程对象
3.执行线程任务:ExecutorService 中的方法
Future<?> submit(Runnable task) 提交一个Runnable任务用于执行
Future<?> submit(Callable
task) 提交一个Callable任务用于执行 4.submit方法的返回值:Future接口
用于接收run方法或者call方法返回值的,但是run方法没有返回值,所以可以不用Future接收,执行call方法需要用Future接收
Future中有一个方法: V get() 用于获取call方法返回值
5.ExecutorService 中的 方法
void shutdown() 启动有序关闭,其中先前提交的任务将被执行,但不会接收任何新任务
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行了");
}
}
public class Test {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new MyRunnable());
es.submit(new MyRunnable());
es.submit(new MyRunnable());
es.shutdown();
}
}
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 1;
}
}
public class Test2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Integer> future = es.submit(new MyCallable());
System.out.println(future.get());
es.shutdown();
}
}
定时器_Timer
1.概述:定时器
2.构造:
Timer()
3.方法:
void schedule(TimerTask, Date firstTime,long period)
task: 抽象类,是Runnable的一个实现类
firstTime:从什么时间开始执行
period: 每个多长时间执行一次,设置的是毫秒值。周期
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Demo01Timer {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("金莲对杨旭说,旭哥该起床了");
}
},new Date(),2000L);
}
}