线程有关知识学习

一、线程三种创建方式

1、Thread class :继承Thread类

2、Runnable接口:实现Runnable接口

3、Callable接口:实现Callable接口

二、创建线程方式一:继承Thread类

1、自定义线程类继承Thread类,重写run()方法,编写线程执行体,创建线程对象,调用start()方法启动线程。

2、总结:线程开启不一定立即执行,需cpu调用。

3、示例:

public class MyThread extends Thread{
    @override
    public void run(){
        方法体;
    }
    public static void main(String [] args){
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

注:不建议使用继承Thread类,避免OOP单继承的局限性。

三、创建线程方式二:实现Runnable接口

1、定义MyRunnable类实现Runnable接口,实现run()方法,编写线程执行体,创建线程对象,调用start()方法启动线程。

2、示例:

public class MyThread implements Runnable{
    @override
    public void run(){
        方法体;
    }
    public static void main(String [] args){
        MyThread myThread = new MyThread();
        //创建三个线程t1、t2、t3
        Thread t1 = new Thread(myThread);
        Thread t2 = new Thread(myThread);
        Thread t3 = new Thread(myThread);
        //执行t1、t2、t3三个线程
        t1.start();
        t2.start();
        t3.start(); 
    }
}

注:推荐使用实现Runnable接口方式,因为避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用。

四、创建线程方式三:实现Callable接口

1、实现Callable接口,需要返回值类型

2、重写call方法,需要抛出异常

3、创建目标对象

4、创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);

5、提交执行:Future <Boolean> result = ser.submit(1);

6、获取结果:boolean flag = result.get();

7、关闭服务:ser.shutdownNow();

8、示例:

public class MyThread implements Callable<Boolean>{
    @override
    public Boolean call(){
        方法体;
    }
    public static void main(String [] args){
        MyThread myThread = new MyThread();
        //创建三个线程t1、t2、t3
        Thread t1 = new Thread(myThread);
        Thread t2 = new Thread(myThread);
        Thread t3 = new Thread(myThread);
        //创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //提价三个执行
        Futurn<Boolean> r1 = ser.submit(t1);
        Futurn<Boolean> r2 = ser.submit(t2);
        Futurn<Boolean> r3 = ser.submit(t3);
        //获取三个执行结果
        boolean rs1 = r1.get();
        boolean rs1 = r1.get();
        boolean rs1 = r1.get();
        //关闭服务
        ser.shutdownNow();
    }
}

五、静态代理模式总结

1、真实对象和代理对象都要是实现同一个接口

2、代理对象要代理真是角色

3、好处:代理对象可以做很多真是对象做不了的事情,真实对象专注做自己的事情

六、Lambda表达式

1、函数式接口:接口里面只有一个方法。

2、示例:

//lambda表示简化
Ilove love = (int a)->{
    System.out.printIn("i love you-->" + a);
};
//简化1:参数类型,多个参数也可以去掉参数类型,要去掉就都去掉,不过必须加上括号
love = (a)->{
    System.out.printIn("i love you-->" + a);
};
//简化2:简化括号,针对于一个参数
love = a->{
    System.out.printIn("i love you-->" + a);
};
//简化3:去掉花括号,只有一行代码时才能去掉花括号,如果有多行,则需用花括号(代码块)包裹起来
love = a->System.out.printIn("i love you-->" + a);

注:使用Lambda表达式前提是接口必须为函数式接口。

七、线程状态

1、五大状态:

image-20231125195954820

2、图解详细分析

image-20231125201326652

八、线程方法

1、线程休眠(sleep(时间)):指定当前线程阻塞的毫秒数;1000ms=1s。

sleep存在异常InterruptedException;

sleep时间达到后线程进入就绪状态;

sleep可以模拟网络延时、倒计时等;

每一个对象都有一个锁,sleep不会释放锁。

2、线程礼让(yield()):礼让线程,让当前正在执行的线程暂停,但不阻塞,将线程从运行状态转为就绪状态,让cpu重新调度,礼让不一定成功,看cpu心情。

3、线程强制执行:等待该线程执行完成后,再执行其他线程,导致其他线程阻塞。

九、线程状态观测

1、Thread.State的枚举值:

    • NEW 尚未启动的线程处于此状态。

    • RUNNABLE 在Java虚拟机中执行的线程处于此状态。

    • BLOCKED 被阻塞等待监视器锁定的线程处于此状态。

    • WAITING 正在等待另一个线程执行特定动作的线程处于此状态。

    • TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。

    • TERMINATED 已退出的线程处于此状态。

十、线程优先级

1、范围从1~10,默认为5,Thread.MIN_PRIORITY = 1;Thread.MAX_PRIORITY = 10;Thread.NORM_PRIORITY = 5;先设置线程优先级,再启动线程。

十一、守护线程(比如:GC(JVM中的垃圾回收机制))

1、线程分为用户线程和守护线程。

2、虚拟机必须确保用户线程执行完毕,而不用等待守护线程执行完毕。

3、守护线程:后台记录操作日志、监控内存、垃圾回收等待。

4、thread.setDaemon(true);//默认是false表示用户线程,true为守护线程

十二、线程同步机制

1、概念:一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。

2、并发:多个线程访问同一个对象。

3、线程同步的安全性的形成条件:队列+锁

4、锁机制实现线程同步,用synchronized关键字(隐式锁)

5、同步方法:在修饰方法中synchronized关键字进行修饰。

同步方法缺点:若将一个打的方法申明为synchronized,将会影响效率。

解决方法:将方法里需要修改的内容才需要加锁,锁太多,浪费资源。

6、同步块:synchronized(Obj obj){}

Obj称为同步监视器,可以是任何对象,但推荐使用共享资源作为同步监视器。

同步方法无需指定同步监视器,因为同步方法的同步监视器就是this,即这个对象本身或者是class。

十三、JUC(并发编程)

1、CopyOnWriteArrayList是JUC安全类型的集合

十四、死锁

1、概念:多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有"两个以上对象的锁"时,就可能会发生"死锁"的问题。

2、产生死锁的四个必要条件:

a、互斥条件:一个资源每次只能被一个进程使用。

b、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

c、不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。

d、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

3、避免死锁方法:破以上四个必要条件的一个或多个条件即可。

十五、Lock(锁)

1、是显示定义锁,是显示加锁

2、示例

//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
//加锁
try{
    lock.lock();
    //被加锁的执行代码
}finally{
    //解锁
    lock.unlock();
}

3、synchronized与Lock的对比

a、Lock是显示锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放。

b、Lock只有代码块锁,synchronized有代码块锁和方法锁

c、使用Lock锁,JVM将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)

d、优先使用顺序:Lock>同步代码块>同步方法

十六、线程通信:

1、方法:

wait():线程一直等待,直到其他线程通知,与sleep不同,会释放锁。

wait(long timeout):指定等待的毫秒数

notify():唤醒一个处于等待状态的线程

notifyAll():唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度。

2、生产者消费者模型的两个方法:管程法、信号灯法

注:均是Object类的方法,都只能在同步方法或同步代码块中使用,否则会抛出异常lllegalMonitorStateException。

十七、线程池

1、ExecutorService:真正的线程池接口,常见子类:ThreadPoolExecutor。

2、void execute(Runnable command):执行任务命令,没有返回值,一般用于执行Runnable。

3、<T> Futurn<T>submit(Callable<T>task):执行任务,有返回值,一般用于执行Callable

4、void shutdown():关闭连接池。

5、Executors:工具类,线程池的工厂类,用于创建并返回不同类型的线程池。

6、示例:

//创建服务,创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
......
//关闭连接
service.shutdown();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值