● 并发:在同一时间,同时发起很多请求,一起执行
● 并行:在同一时间,同时发起很多请求,但没有同时执行
● 多线程的实现方式
○ 1、继承 方式
ⅰ. 创建子类继承Thread类
ⅱ. 覆写父类的run方法
ⅲ. 主线程中创建子线程对象
ⅳ. 调用子线程对象的start方法开启子线程
public class Thread_01 extends Thread{
@Override
public void run() {
System.out.println("子类的run方法");
for (int i = 40; i < 100; i++) {
System.out.println("##**");
}
}
}
public static void main(String[] args) {
Thread t = new Thread_01();
t.start();
for (int i = 0; i < 30; i++) {
System.out.println(i);
}
}
○ 2、实现方式
ⅰ. 创建子类,实现Runnable接口
ⅱ. 覆写run方法
ⅲ. 主线程创建Thread对象,把子线程当作实际参数传入构造器
ⅳ. 调用Thread的start方法,开辟子线程
public class Thread_02 implements Runnable {
@Override
public void run() {
System.out.println("实现方式的run方法");
Thread.currentThread().setName("实现方式的子线程");
System.out.println(Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread t = new Thread(new Thread_02());
t.start();
}
● 区别和联系
○ 联系:都是多线程的方式
○ 区别:实现方式比继承好一些,避免的单继承的局限性
■ 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源
● 常用方法
○ getName
○ setName
● 生命周期
○ 新建
○ 就绪;处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
○ 运行;当就绪的线程被调度并获得CPU资源时,便进入运行状态, run()方法定义了线 程的操作和功能
○ 阻塞,在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态,阻塞结束后再次进入就绪状态
○ 消亡;
● sleep
○ 1、写在哪就是让对应的线程沉睡,
○ 2、调用interrupt方法可以唤醒沉睡的线程,但是会主动抛出异常
● Stop
○ 结束线程
● join
○ 1、合并线程,写在哪就是和哪个线程合并
○ 2、谁调用就等谁先执行完,在执行当前线程
● yield()让出cpu,当前线程进入就绪队列等待调度
○ 同优先级让位
○ 让位不一定下一个不是自己
● 线程同步
● 如何让线程同步
○ 1、给方法加上synchronized修饰相当于加锁,当有线程执行加锁的成员方法时,所有加锁的方法和加锁的代码块都被锁住,无法访问,只有等该线程释放锁,才可以继续访问
○ 2、同步代码块
■ 给要操作的代码加上代码块synchronized(){},在成员方法内括号里要写this
■ 当有线程执行加锁的代码块,所有加锁的代码块和加锁的方法都被锁住,无法访问,只有等该线程释放锁,才可以继续访问
■ 补充:synchronized(){}如果写在静态方法内部,也可实现对静态数据的同步,但是括号内要写类名.class
○ 总结:synchronized修饰的方法,同一时间片内,只允许一个线程访问该方法和一起加synchronized修饰的代码块
○ 3、Lock
■ Lock lock = new ReentrantLock()
■ lock.lock()加锁
■ lock.unlock()解锁
○ 建议使用优先级:Lock > 同步代码块 > 同步方法