创建线程的两种方式
第一种 继承Thread类
1.定义类继承Thread类
2.重写run方法 线程任务
3.开启线程
创建子类对象 调用start方法
第二种 实现Runnable接口
1.定义类实现Runnable接口
2.重写run方法 线程任务
3.开启线程
创建实现类对象
创建Thread类对象 将实现类对象传递
调用Thread类start方法
为什么创建线程要继承Thread类? 因为Thread就是线程类,具备线程的属性和功能 ,比如start方法
既然Thread类就是线程类 为什么不直接创建Thread类对象开启线程呢?
java Threat t = new Thread(); t.start();
虽然这样也开启了线程 但是执行的是Thread类的run方法 这个run方法并不是我们 想要执行的,继承Thread类 可以重写run方法
而这个run方法中的内容是我们想要执行的
为什么有继承Thread的方式 还要有实现Runnable接口的方式?
1.接口的方式避免了单继承的局限性 如果一个类已经有了父类 还想开线程 是没有办法通过继承Thread类的方式开启的 只能通过实现接口的方式
2.线程任务和线程进行解耦合 第一种方式 定义的子类即是线程类 又包含了线程任务 将线程类和线程任务耦合到了一起 第二种方式 定义的实现类只是线程任务类 将线程任务和 线程分开3.更容易实现 多个线程共享1个资源
wait 和sleep的区别 wait是Object类的方法 必须由锁对象调用 也就是必须在同步内使用
当线程遇到wait方法 进入到等待状态 同时会释放掉锁 必须得唤醒 当其他线程唤醒后 ,这条等待的线程不是立即执行
而是先去获取锁 获取到锁后才能执行
sleep是Thread类的静态的方法 Thread类直接调用 既可以在同步外使用 也可以在同步内使用 如果在同步内使用,当线程遇到sleep方法后 会进入到睡眠状态 但是 不会释放锁
当睡眠时间到了 继续执行 出了同步 才会释放锁join方法是让 当前线程等待,调用方法的线程进行插队先执行,执行完毕后,在让当前线程执行.对其他线程没有任何影响.注意此处的当前线程不是调用方法的线程
而是Thread.currentThread().
线程不安全:当多条线程操作同一个资源 可能会出现数据错误 数据不安全
那么如何解决?
线程同步:有锁的线程执行 没锁的线程等待
同步代码块
synchronized(任意对象){
可能出现问题的代码
}
同步方法
在方法的返回值类型之前 加上 synchronized
同步方法有没有锁? 有锁 锁是this
同步方法可以是静态的吗? 可以
锁还是this吗? 肯定不是 因为静态中不能使用this/super
那么锁是谁? 当前类名.class
Lock
实现类
ReentrantLock
方法
lock() 获取锁
unlock()释放锁
线程状态 见图