多线程的基础知识
- java的多线程是挂在对象上的,并不是在方法上。每个对象都有一个锁,当遇到类似synchronized的同步需要时,就会监视每个想使用本对象的线程按照一定的规则来访问,规则也就是在同一时间内只能有一个线程访问此对象。
- java中获取锁的单位是线程。当线程A获取了对象B的锁,也就是对象B的持有标记上写的是xianchengA的唯一标识,在需要同步的情况下,只有线程A能访问对象B。
- Thread常用方法有:start (启动线程,调用当前线程的run),stop,sleep,join(线程a中调用线程b的join方法,此时线程a会进入阻塞状态,等待线程b执行完,线程a才结束阻塞状态),yield(释放CPU的执行权),isAlive(判断当前线程是否存活)等,他们是线程级别的方法,所以并不会太关心锁的具体逻辑
- Object的线程有关方法是:wait,notify,notifyAll他们是对象的方法,所以使用的时候有点憋屈,必须当前线程获取了本对象的锁才能使用,否则会报异常,他们能更细粒的控制锁,可以释放锁
进程和线程的区别
- 进程可以细化分为多个线程
- 每个线程都有自己独立的 栈 和 程序计数器
- 多个线程共享同一个进程中的结构 堆 和 方法区
多线程的优点:
- 提高应用程序的相应,对图形化界面更有意义,增强用户体验
- 提高计算机系统CPU的利用率
- 改善程序结构,将复杂的进程分为多个线程,独立运行,利于理解和改善
比较多线程创建的两种方式(实则四种)
继承Thread类 实现Runnble接口 实现Callable接口 创建线程池
- 优先选择,实现Runnble接口的形式
- 原因:a 实现的方式没有类的单继承的局限性 b 实现的方式更适合来处理多个线程共享数据的情况
- 联系:Thread 类 也实现了 Runnble接口
- 相同点:两种方式都需要重写run()。将线程要执行的逻辑声明在run()中
- 实现Callable接口比实现Runnble接口强大在哪? 1)Call方法有返回值 2)可以抛异常 3)Callable支持泛型
- 使用线程池:1)提高响应速度 2)降低资源消耗 3)便于线程管理(线程池大小,最大线程数)
多线程的几种状态
- 创建 当一个Thread类或者其子类被声明并创建时,新生的线程处于创建
- 就绪 当线程调用start()方法时,进入线程队列等待CPU分配资源
- 运行 线程被调度并获得cpu资源,run()方法定义了线程的操作和功能
- 阻塞 在某种特殊情况下被人为挂起, 让出cpu并临时终止自己的行为
- 死亡 线程完成工作被提前强制地终止或出现异常导致
线程的调度以及设置线程的优先级
- 调度策略 =》时间片 抢占式
- java的调度方法
- 线程的优先级:maxPriority(10) minPriority(1) normPriority(5)
- 获取和设置当前线程的优先级: getPriority setPriority(int n)
解决线程安全的方法,以及他们的区别
- 在java中我们通过同步机制来控制线程的安全:同步代码块,同步方法,Lock锁
- 解决方法 : 有 synchornized(同步代码块和同步方法) 和 lock(5.0后的新特性)锁
- 不同点: synchornized机制执行完同步代码块或者同步方法,可以自动释放锁(同步监视器) Lock锁需要手动启动同步(lock), 同时结束同步也需要手动关闭(unLock)
线程中的死锁问题
- 理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己所需要的同步资源,形成死锁
线程通讯方法,注意事项(例子,两条线程交叉打印1-100数字)
- wait() 此方法使当前线程进入阻塞状态,释放对象锁 notify() 此方法会唤醒一个被wait()的线程,如果有多个被wait(),选择优先级高的 notifyAll() 此方法会唤醒所有被wait()的线程
- 注意:a 这三个方法必须使用在同步代码块或者同步方法中 b 这三个方法的调用者同步代码块的同步监视器
线程中sleep() 和 wait() 区别
- 相同点:都会使线程进入阻塞状态
- 不同点: 1)声明位置不同 sleep()属于Thread类,wait()属于Object类 2)调用要求不同 sleep()任何情况下都能调,wait()必须使用在同步代码块调用 3)是否释放锁 两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁