线程的基础知识

线程的概念

Java中线程的启动

继承Thread类型创建线程

  • 定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
  • 创建Thread子类的实例,即创建了线程对象。
  • 调用线程对象的start()方法来启动该线程。

实现Runnable接口创建线程

  • 定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  • 创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
  • 调用线程对象的start()方法来启动该线程

通过Future和Callable创建线程

  • 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
  • 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
  • 使用FutureTask对象作为Thread对象的target创建并启动新线程。
  • 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

使用线程池例如Excutor框架(工厂的方法)

  • 创建线程池
    • 创建线程池的三大方式 Executors的静态方法
      • Executors.newSingleThreadExecutor()
      • Executors.newFixedThreadPool(n)
      • Executors.newCachedThreadPool()
    • 自行创建线程池的七大参数 new ThreadPoolExecutor
  • 执行WxecutorServices.execute(Runnable command)

创建线程的方式的对比

  1. 采用实现Runnable、callable接口的方式创建线程

线程了只是实现了Runnble接口或者Callable接口,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU,代码和数据分开。但是,缺点是编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread

​ 2、使用继承Thread类的方式创建多线程

如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可 获得当前线程。缺点是线程类已经继承了Thread类,就不能再继承其他父类了

​ 3、Runnable和Callable的区别

  • Callablle规定重写的方法是call(),Runnable规定(重写的方法)是run
  • Callable的任务执行后可以返回值,而Runnavle的任务是不能返回值的
  • call的方法可以抛出异常,run方法不可以
  • 运行Callable任务可以拿到一个Future对象,表示异步计算的结果,它提供了检查计算是否完成的情况,可以取消任务的执行,还可获取执行结果

线程的状态

在Thread.state类中进行了定义

新建状态 表示刚刚创建的线程,这些线程还没有执行

可运行 可能正在运行,也饿能正在等待CPU时间片

阻塞 等待获取一个排他锁,其他线程释放了锁就会结束此状态

无线期等待 等待其他线程显示的唤醒,否则不会被分配CPU时间片

限期等待:无须等待其他线程显示的唤醒,在一定时间之后会被系统自动唤醒

死亡:可以是线程结束之后自己结束,或者产生了异常而结束

线程的常用方法

基本操作

  1. Daemon

    当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程

  2. sleep

    Thread.sleep(millsec)方法会休眠当前正在执行的线程,millsec单位是毫秒(==抱着锁睡觉)

  3. yield 礼让

    对静态方法thread.yield()的调用声明了当前线程已经完成了声明周期最重要的部分,可以切换给其他线程来执行

  4. join

    一直阻塞当前线程直到目标线程执行完毕

  5. start

    启动线程

  6. new

    创建线程

线程协作

  1. wait notify() 和notifyall() (工作在同步代码块中-

    使用wait()挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其他线程就无法进入对象 的同步方法或同步控制块中,那么就无法执行notify或者notifyAll来唤醒挂起的线程,造成死锁

    工作流程

    • 一个线程调用了object.wait(),它就会进入object对象的等待队列;这个等待队列中,可能会有多个线程,因为系统运行多个线程同时等待某个对象
    • 当object.notify()被调用时,它就会从这个等待队列中,随机选择一个线程,并将其环形
    • 方法不能随便调用,必须包含在对应的synchronized中
    • 会自动释放锁
  2. wait和sleep的区别

    • 来自不同的类
    • 关于锁的释放: wait会释放目标对象的锁,sleep不会释放任何资源
    • 使用的范围的不同: wait必须工作在synchromnized中

    3、await()、signal和singalAll()

    • java.util.concurrent 类库中提供快乐Condition类来实现线程之间的协调
    • 可以在Condition上调用await()来使得线程等待,其他线程调用singal()和singalAll()来唤性等待的线程
    • 相比于wait这种等待方式,await可以指定等待的条件,因此更加灵活
    class Data3{ // 资源类 Lock
    
        private Lock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
        private int number = 1; // 1A  2B  3C
    
        public void printA(){
            lock.lock();
            try {
                // 业务,判断-> 执行-> 通知
                while (number!=1){
                    // 等待
                    condition1.await();
                }
                System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");
                // 唤醒,唤醒指定的人,B
                number = 2;
                condition2.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void printB(){
            lock.lock();
            try {
                // 业务,判断-> 执行-> 通知
                while (number!=2){
                    condition2.await();
                }
                System.out.println(Thread.currentThread().getName()+"=>BBBBBBBBB");
                // 唤醒,唤醒指定的人,c
                number = 3;
                condition3.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void printC(){
            lock.lock();
            try {
                // 业务,判断-> 执行-> 通知
                // 业务,判断-> 执行-> 通知
                while (number!=3){
                    condition3.await();
                }
                System.out.println(Thread.currentThread().getName()+"=>BBBBBBBBB");
                // 唤醒,唤醒指定的人,c
                number = 1;
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值