Java多线程01
Process 与 Thread
进程 : 执行程序的一次过程, 是一个动态的概念. 是系统资源分配的单位
线程 : 一个进程中可以包含若干个线程. 是CPU调度和执行的最小单位
核心概念
- 线程就是独立的执行路径
- 在程序运行时, 即使自己没有创建线程, 后台也会有多个线程, 如主线程和 gc 线程等
- main() 称之为主线程, 是系统的入口, 用于执行整个程序
- 在一个进程中, 如果开辟了多线程, 线程的运行由调度器安排调度, 调度器是与操作系统紧密相关的, 先后顺序不受人为干预
- 对同一份资源操作时, 会存在资源抢夺问题, 需要加入并发控制
- 线程会带来额外的开销, 如CPU调度时间, 并发控制开销
- 每个线程在自己的工作内存交互, 内存控制不当会造成数据不一致
线程创建
- Thread class : 继承 Thread 类
- Runnable 接口 : 实现 Runnable 接口
- Callable 接口 : 实现 Callable 接口
调用 run 方法和 start 方法的区别
调用 start 方法才能实现多线程效果!
继承Thread类
package com.guanxing.lesson01;
//创建线程方式一:继承Thread类, 重写run()方法, 调用start开启线程
//总结:注意! 线程开启不一定立即执行, 由cpu调度
public class TestThread extends Thread{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码---" + i);
}
}
public static void main(String[] args) {
//main线程, 主线程
//创建一个线程对象, 调用start方法开启线程
TestThread testThread1 = new TestThread();
// testThread1.run();
testThread1.start();
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程---" + i);
}
}
}
实现Runable接口
package com.guanxing.lesson01;
//创建线程方式二:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class TestThread2 implements Runnable{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 500; 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);
}
}
}
小结
- 继承Thread类
- 启动线程:子类对象.start()
- 实现Runnable接口
- 启动线程:传入目标对象+Thread对象.start()
- 推荐使用!
TestThread testThread1 = new TestThread();
testThread1.start();
TestThread2 testThread2 = new TestThread2();
Thread thread = new Thread(testThread2);
thread.start();
静态代理模式
package com.guanxing.StaticProxy;
//静态代理模式总结:真实对象和代理对象都要代理同一个接口!
//代理对象要代理真实角色
//好处:
//代理对象可以做很多真实对象做不了的事情
//真实对象专注做自己的事情
public class StaticProxy {
public static void main(String[] args) {
//实例化用户jay
User jay = new User();
//将用户jay丢给婚庆公司
WeddingCompany weddingCompany = new WeddingCompany(jay);
weddingCompany.HappyMarry();
//静态代理和线程的类比
// new 代理类( 真实对象 ).执行方法;
new Thread( ()-> System.out.println("我爱你") ).start();
new WeddingCompany(new User()).HappyMarry();
}
}
//实现一个结婚接口
interface Marry {
void HappyMarry();
}
//定义一个用户类
//真实对象
class User implements Marry {
@Override
public void HappyMarry() {
System.out.println("我要结婚了,超开心!");
}
}
//定义婚庆公司类
//代理角色,代理用户去结婚
class WeddingCompany implements Marry {
//要代理的真实角色
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();
target.HappyMarry();
after();
}
private void before() {
System.out.println("婚礼之前,布置现场");
}
private void after() {
System.out.println("婚礼之后,收尾款...");
}
}
Lambda表达式
函数式接口:
- 只包含唯一一个抽象方法的任意接口
- 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
public interface Runnable {
public abstract void run();
}
演变推导
package com.guanxing.lambda;
/*
推导lambda表达式
*/
public class TestLambda01 {
//3.静态内部类
static class Like2 implements ILike {
@Override
public void lambda() {
System.out.println("i like lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.lambda();
like = new Like2();
like.lambda();
//4.局部内部类
class Like3 implements ILike {
@Override
public void lambda() {
System.out.println("i like lambda3");
}
}
like = new Like3();
like.lambda();
//5.匿名内部类(没有类的名称,必须借助接口或父类)
like = new ILike() {
@Override
public void lambda() {
System.out.println("i like lambda4");
}
};
like.lambda();
//6.用lambda简化
like = () -> {
System.out.println("i like lambda5");
};
like.lambda();
}
}
//1.定义一个函数式接口
interface ILike {
void lambda();
}
//2.实现类
class Like implements ILike {
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
package com.guanxing.lambda;
public class TestLambda02 {
public static void main(String[] args) {
// ILove love = (int a) -> {
// System.out.println("i love you--->"+a);
// };
// love.love(520);
//终极简化版
ILove love = null;
love = a -> System.out.println("i love you--->"+a);
love.love(520);
//总结:
//lambda表达式在只有一行代码的情况下才能去掉花括号!
//前提是接口为函数式接口
//多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
}
}
//定义函数时接口
interface ILove {
void love(int a);
}
优点:
- 避免匿名内部类定义过多
- 简化代码,只留下核心逻辑