线程
线程创建的第一种方式
继承Thread类
为什么要继承Thread类?
Thread类就是线程类,具有线程最基本的属性和功能 比如 设置线程名 开启线程
继承Thread类 就可以直接使用这些功能.
那为什么不直接创建Thread类对象 开启线程?
Thread t = new Thread();
t.start();
这样虽然开启了线程 但是运行的是Thread类的run方法 ,这个run方法中执行的内容
并不是我们想要的,所以我们继承Thread类 重写run方法 这样运行的就是我们自己的run方法
1.定义一个类继承Thread类
2.重写run方法 (线程任务)
3.开启线程
创建子类对象
调用Thread类的start方法
线程名称获取和设置
Thread类
方法
String getName() 获取线程名
static Thread currentThread() 获取到当前线程对象
void setName(String name) 设置线程名
线程创建的第二种方式
实现Runnable接口
为什么有了继承的方式 还要有实现接口的方式?
1.实现Runnable接口的方式 避免了单继承的局限性
如果一个类已经有了父类 还想开启线程 只能通过实现接口的方式
2.解耦合 线程任务和线程对象分离
3.更符合面向对象 更容易实现 多个线程共享一个任务
1.定义实现类 实现 Runnable接口
2.重写run方法 (线程任务)
3.开启线程
创建实现类对象
创建Thread对象 传入线程任务
public Thread(Runnable r)
调用Thread的start方法 开启线程
匿名内部类
作用:临时创建一个类子类对象的快捷方式
格式
new 父类/接口(){
重写方法
}
匿名内部类开启线程
Thread
Thread的静态方法
public static void sleep(long time) 当前线程 休眠time毫秒后 醒来继续执行
//静态1秒
Thread.sleep(1000);
线程优先级
1-10 1最低 10最高 5默认
public final void setPriority(int newPriority)更改线程的优先级。
public static final int MIN_PRIORITY //1 最低优先级
public static final int NORM_PRIORITY //5 默认优先级
public static final int MAX_PRIORITY //10 最大优先级
t1.setPriority(Thread.MAX_PRIORITY);
用户线程
我们正常写的代码都是用户线程
守护线程
用户线程存在 守护线程可以执行 用户线程执行完 守护线程即使没执行完 jvm也直接退出
GC就是一个守护线程
//如果将t1设置为守护线程 t2执行完 t1就不再执行 jvm直接退出
t1.setDaemon(true);
public final void setDaemon(boolean on) on的值为true将线程设置为守护线程,注意一定要在开启线程之前设置
join
join方法是让 当前线程等待,调用方法的线程进行插队先执行,执行完毕后,在让当前线程执行.
对其他线程没有任何影响.
注意 此处的当前线程不是调用方法的线程 而是Thread.currentThread().
线程安全问题
当多条线程访问同一个资源 可能出现数据错误 线程不安全
解决方法:线程同步
同步代码块
synchronized(任意对象 ){
可能出现问题的代码
}
同步方法
在方法的返回值类型 之前 加上 synchronized关键字
同步方法有锁吗? 有 锁是谁? this
同步方法可以是静态的吗? 可以 此时锁还是this吗? 绝对不是
那么静态的同步方法 锁是谁? 当前类名.class
Lock接口
方法
void lock() 获取锁
void unlock() 释放锁
常用实现类
ReentrantLock
Lock l = new ReentrantLock();
l.lock();
l.unlock();Object
java.lang.Object
方法
void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void wait(long time) 在time时间内 有人唤醒就唤醒了 否则时间到了 就自己醒来
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
调用
wait和notify必须由锁对象调用 必须在同步中使用
线程遇到wait方法 会进入到等待状态 同时 释放锁对象
当其他线程调用notify方法时 ,会唤醒在此对象监视器上等待的单个线程,注意 此时线程虽然被唤醒 但是不能立即执行
需要先获取到锁 然后才能执行
Object obj = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj){
System.out.println("开始等待");
try {
obj.wait();
System.out.println("已经被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
Thread.sleep(5000);
//唤醒正在等待的线程
synchronized (obj){
System.out.println("开始唤醒");
obj.notify();
}
wait和sleep区别
sleep是Thread类的静态方法 休眠到时间后自动醒来执行 在同步外可以使用 在同步内也可以使用
需要注意 如果sleep方法 在同步中使用 不会释放锁
wait是Object类的方法 必须由锁对象调用 也就是必须在同步内使用 线程遇到wait方法会释放锁对象
可以是其他线程 使用notfiy唤醒 也可以使用重载方法 时间到自己醒