1、线程简介
2、线程实现(重点)
2.1、线程创建:
2.1.1、Thread class(继承Thread类)
线程开启不一定立即执行,由cpu调度执行。
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
public class testthread extends Thread{
@Override
public void run() {
for(int i=0;i<200;i++) {
System.out.println("我在学习多线程"+i);
}
}
public static void main(String[] args) {
testthread testthread1 = new testthread();
testthread1.start();
for(int i=0;i<1000;i++) {
System.out.println("我在学习kuangstudy的java课程"+i);
}
}
}
2.1.2、Runnable接口(常用)
//创建线程方式二:实现runable接口,重写run()方法,执行线程需要丢入runable接口
public class testthread implements Runnable{
@Override
public void run() {
for(int i=0;i<200;i++) {
System.out.println("我在学习多线程"+i);
}
}
public static void main(String[] args) {
//创建runable接口的实现类对象
testthread testthread1 = new testthread();
//创建线程对象,通过线程对象开启线程
//Thread thread = new Thread(testthread1);
//thread.start();
new Thread(testthread1).start();
for(int i=0;i<1000;i++) {
System.out.println("我在学习kuangstudy的java课程"+i);
}
}
}
//Runable:同一个对象被多个线程使用
public class testthread implements Runnable{
private int tickets = 10;
@Override
public void run() {
while(true) {
if (tickets <= 0) {
break;
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickets--+"张票");
}
}
public static void main(String[] args) {
//创建runable接口的实现类对象
testthread ticket = new testthread();
//创建线程对象,通过线程对象开启线程
//Thread thread = new Thread(testthread1);
//thread.start();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛党").start();
}
}
2.1.3、Callable接口(了解即可)
//1实现callable接口,需要返回值类型;
//2.重写call方法,需要抛出异常
//3.创建目标对象
//4.创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(1);
//5.提交执行:
Future<Boolean> result1 = ser.submit(t1);
//6.获取结果:
boolean r1 = result1.get();
//7.关闭服务:
ser.shutdownNow();
小结
1.继承Thread类:
- 子类继承Thread类具备多线程能力;
- 启动线程:子类对象.start();
- 不建议使用:避免oop单继承局限性;
2.实现runable接口;
- 实现接口Runable接口具备多线程能力;
- 启动对象:传入目标对象+Thread对象.start();
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用;
3.Callable接口(了解即可)
2.2、静态代理模式
- 真实对象和代理对象都要实现同一个接口;
- 代理对象要代理真实角色;
好处:
- 真实对象专注于做自己的事;
- 代理对象可以做真实对象做不了的事;
public class staticproxy {
public static void main(String[] args) {
//你要结婚,你是目标
YOU you = new YOU();
//把你丢给婚庆公司
WeddingHelp weddingHelp = new WeddingHelp(you);
//婚庆公司帮助你结婚
weddingHelp.HappyMarry();
//以上可归为这一句
//new WeddingHelp(new YOU()).HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
//真实角色
class YOU implements Marry{
@Override
public void HappyMarry() {
System.out.println("你要结婚了,很开心!");
}
}
//代理角色,给你结婚提供帮助
class WeddingHelp implements Marry{
private Marry project;
public WeddingHelp(Marry project){
this.project=project;
}
@Override
public void HappyMarry() {
before();
this.project.HappyMarry();
after();
}
private void before(){
System.out.println("结婚前,布置婚礼现场");
}
private void after(){
System.out.println("结婚后,收份子钱");
}
}
2.3、Lamda表达式
1.为什么要用lamda表达式?
- 避免匿名内部类定义过多
- 使代码看起来更简洁
- 去掉了一堆没有意义的代码,只留下核心的逻辑
2.Functional Interface(函数式接口)是lamda表达式的关键所在
- 任何接口,如果只包含唯一一个抽象方法,那它就是函数式接口
- 对于函数式接口,我们可以通过lamda表达式创建该接口的对象
public class TestLamda {
public static void main(String[] args) {
ILike like =new Like();
like.like(520);
}
}
interface ILike{
void like(int a);
}
class Like implements ILike{
@Override
public void like(int a) {
System.out.println("我喜欢-->"+a);
}
}
2.静态内部类:
public class TestLamda {
static class Like implements ILike{
@Override
public void like(int a) {
System.out.println("我喜欢-->"+a);
}
}
public static void main(String[] args) {
ILike like =new Like();
like.like(520);
}
}
interface ILike{
void like(int a);
}
3.局部内部类:
public class TestLamda {
public static void main(String[] args) {
class Like implements ILike{
@Override
public void like(int a) {
System.out.println("我喜欢-->"+a);
}
}
ILike like =new Like();
like.like(520);
}
}
interface ILike{
void like(int a);
}
4.lamda表达式:
public class TestLamda {
public static void main(String[] args) {
ILike like =(int a)->{
System.out.println("我喜欢-->"+a);
};
like.like(520);
}
}
interface ILike{
void like(int a);
}
5.lamda表达式简化:
注意:
- lamda表达式只有一行代码的情况下才能简化为一行,如果有多行,必须用代码块包裹,如花括号;
- 前提是接口必须为函数式接口;
- 多个参数也可以去掉参数类型,要去掉必须全部去掉,且必须加上括号;
public class TestLamda {
public static void main(String[] args) {
ILike like =(int a)->{
System.out.println("我喜欢-->"+a);
};
//简化1:去变量名
like = (a) -> {
System.out.println("我喜欢-->" + a);
};
//简化2:去括号
like = a -> {
System.out.println("我喜欢-->" + a);
};
//简化3:去花括号
like = a -> System.out.println("我喜欢-->" + a;
like.like(520);
}
}
interface ILike{
void like(int a);
}
3、线程状态
状态:
方法:
3.1、线程停止 Flag
- 建议线程正常停止—利用次数,不建议死循环
- 建议使用标志位—设置一个标志位
- 不要使用stop和destory等jdk不建议使用的方法
3.2线程休眠 Sleep
3、线程礼让 Yield
4.线程强制执行 Join
5.观测线程状态 State
6.线程优先级
7.守护线程 Daemon
线程同步(重点)
- 同步方法和同步块
- 死锁
3.lock锁:
class A{
//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
public void main(){
try{
lock.lock();//加锁
/*
需要保证线程体安全的代码
*/
}finally {
lock.unlock();//解锁
}
}
}
Synchronized和Lock的对比:
线程通信问题
1、线程协作(生产者消费者模式)
1.1 管程法
1.2信号灯法
2.线程池
高级线程
…