单线程:有多个任务只能依次执行。当上一个任务执行结束后,下一个任务开始执行。如,去网吧上网,网吧只能让一个人上网,当这个人下机后,下一个人才能上网。
多线程:有多个任务可以同时执行。如,去网吧上网,网吧能够让多个人同时上网。
线程时独立的执行路径,main()为主线程,线程的运行由调度器安排调度,由操作系统决定,人为不能干涉多线程运行先后顺序。
继承Thread类(重点),不建议使用(避免oop单继承局限性)
1.自定义线程类继承Thread类(子类继承Thread类具备多线程能力)
2.重写run()方法,编写线程执行体
3.创建线程对象,调用start()方法启动线程(子类对象.start())
注意:线程开启不一定立即执行,由cpu调度执行
package com.peace.demo01;
public class TestThread1 extends Thread {
@Override
public void run(){
for (int i = 0;i < 200;i++){
System.out.println("我在看代码--"+i);
}
}
public static void main(String[] args) {
//创建一个线程对象
TestThread1 testThread1 = new TestThread1();
//调用start()方法开启线程
testThread1.start();
for (int i = 0;i < 1000;i++){
System.out.println("我在学多线程--"+i);
}
}
}
实现Runnable接口(重点),推荐使用(避免单继承局限性,灵活方便,方便同一个对象被多个线程使用)
1.定义类实现Runnable接口(实现Runnable接口具备多线程能力)
2.重写run()方法,编写线程执行体
3.创建线程对象,调用start()方法启动线程(传入目标对象+Thread对象.start())
package com.peace.demo01;
public class TestThread2 implements Runnable {
@Override
public void run() {
for (int i = 0;i < 200;i++){
System.out.println("我在看代码--"+i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现类对象
TestThread2 testThread2 = new TestThread2();
//创建线程对象,通过线程对象来开启我们的线程,代理
// Thread thread = new Thread(testThread2);
// thread.start();
new Thread(testThread2).start();
for (int i = 0;i < 1000;i++){
System.out.println("我在学多线程--"+i);
}
}
}
package com.peace.demo01;
/**
* 多个线程同时操作同一个对象
* 买火车票的例子
* 发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
*/
public class TestThread3 implements Runnable{
//票数
private int ticketNums = 10;
@Override
public void run() {
while (true){
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (ticketNums <= 0){
break;
}
System.out.println(Thread.currentThread().getName()+"-->拿到了 第"+ticketNums-- +"张票");
}
}
public static void main(String[] args) {
TestThread3 ticket = new TestThread3();
new Thread(ticket,"小明").start();
new Thread(ticket,"小红").start();
new Thread(ticket,"小帅").start();
}
}
实现Callable接口(了解),可以定义返回值,抛出异常
1.实现Callable接口,需要返回值类型
2.重写call方法,需要抛出异常
3.创建目标对象
4.创建执行服务:ExectorService ser = Exectors.newFixedThreadPool(1);1为池数
5.提交执行:Future result1 = ser.submit(t1);
6.获取结果:boolean r1 = result1.get();
7.关闭服务:ser.shutdownNow();
真实对象和代理对象都要实现同一个接口
代理对象要代理真实对象
好处:代理对象可以做很多真实对象做不了的事情,真实对象专注做自己的事情
1.避免匿名内部类定义过多
2.可以让代码看起来很简洁
3.去掉了一堆没有意义的代码,只留下核心的逻辑
其实质属于函数式编程的概念
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
//1.定义一个函数式接口
interface ILike{
void lambda();
}
对于函数式接口,可以通过lambda表达式来创建该接口的对象
package com.peace.lambda;
//推导lamda表达式,从2到6逐步简化代码
public class TestLambda1 {
//3.静态内部类
static class Like2 implements ILike{
@Override
public void lambda(int a) {
System.out.println("I like lambda2-->"+a);
}
}
public static void main(String[] args) {
ILike like = new Like();
like.lambda(1);
like = new Like2();
like.lambda(2);
//4.局部内部类
class Like3 implements ILike{
@Override
public void lambda(int a) {
System.out.println("I like lambda3-->"+a);
}
}
like = new Like3();
like.lambda(3);
//5.匿名内部类,没有类的名称,必须借助接口或者父类
like = new ILike(){
@Override
public void lambda(int a) {
System.out.println("I like lambda4-->"+a);
}
};
like.lambda(4);
//6.用lambda简化定义实现类
like = (int a)->{
System.out.println("I like lambda5-->"+a);
};
like.lambda(5);
//6.1 简化参数类型
like = (a)->{
System.out