线程
创建线程的两种方式
- 继承Thread类,重写run方法
- 实现Runnable接口,重写run方法
注意:Thread类实现了Runnable接口
run方法只是一个普通的方法,没有真正地启动一个线程
start()方法调用start0()方法后,该线程并不一定会立马执行,只是将线程变成了可运行状态,具体什么时候执行,取决于CPU,由CPU统一进行调度
Thread常用方法
public final String getName():获取线程名称
public final synchronized void setName(String name):设置线程名称
public final void setPriority(int newPriority):设置线程优先级
public final int getPriority():获取线程优先级
public static native void sleep(long millis):让线程休眠指定毫秒数
public static boolean interrupted():中断线程
注意:getName、setName、getPriority、setPriority方法都是public类型方法,不能通过类名直接调用。可以使用实例变量调用或通过Thread.currentThread()获取实例再进行调用
public static native void yield():线程的礼让。让出CPU,让其他线程执行,但礼让时间不确定,不一定礼让成功
public final void join():线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程的所有任务
守护线程
守护线程:一般是为用户线程服务的,当所有用户线程结束,守护线程自动结束
常见的守护线程:垃圾回收线程
public class mytest {
public static void main(String[] args) {
T t = new T();
t.setDaemon(true);
t.start();
for (int i=0; i<=10 ; i++) {
System.out.println("主线程运行中");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class T extends Thread {
@Override
public void run() {
while (true) {
System.out.println("守护线程守护中");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程的生命周期
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED

NEW:新建状态
Thread t = new Thread();
线程被创建但还未启动
这里的创建,仅仅是在Java的编程语言层面被创建,而在操作系统层面真正的线程还没有被创建。
只有当调用了 start() 方法之后,该线程才会被创建出来,进入RUNNABLE状态
注意:如果希望调用子线程的start()方法后子线程立即开始执行,程序可以使用Thread.sleep(1) 来让当前运行的线程(主线程)睡眠1毫秒,1毫秒就够了,因为在这1毫秒内CPU不会空闲,它会去执行另一个处于就绪状态的线程,这样就可以让子线程立即开始执行
RUNNABLE:可运行状态
实际上Java线程的可运行状态包括了Ready和Running两种状态
Running指的是已经获得CPU时间片正在运行的线程
Ready指的是线程已经准备就绪,进入线程队列等待系统分配CPU
BLOCKED:阻塞状态
线程为进入 synchronized 方法、代码块等待获取锁而被阻塞
WAITING:无限等待状态
无超时参数的 join()、wait()方法的调用会让当前线程进入等待状态,在该状态下的线程不会被CPU调度,即无限期等待,除非被其他线程显示地唤醒(比如 notify()、notifyAll()、interrupt()方法)
TIMED_WAITING:超时等待状态
有超时时间限制的等待,当超时时间一到,线程就会自行返回,等待被CPU分配时间片。此状态可通过调用设置了超时时间的 join()、wait()、sleep() 方法等方式进入
TERMINATED
线程终止结束
线程同步机制
在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就需要使用同步访问机制,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性
互斥锁
每个对象都对应一个“互斥锁”的标记,这个标记用来保证在任一时刻只能有一个线程访问该对象
关键字synchronized 与对象的互斥锁联系
非静态的同步方法的锁可以是this,也可以是其他对象(要求是同一个对象)
静态的同步方法的锁为当前类本身(当前类.class)
同步的局限性:导致程序的执行效率降低
释放锁
当前线程的同步方法、同步代码块执行完毕会释放锁
当前线程在同步方法、同步代码块遇到break、return会释放锁
当前线程在同步方法、同步代码块中出现了未处理的Error或Exception会释放锁
当前线程在同步方法、同步代码块中执行了线程对象的wait()方法,当前线程会释放锁
下面的操作不会释放锁
线程执行同步方法或同步代码块时程序调用Thread.sleep()、Thread.yield() 方法不会释放锁
线程执行同步方法或同步代码块时其他线程调用了该线程的suspend() 方法将该线程挂起,该线程不会释放锁
线程的死锁
public class mytest {
public static void main(String[] args) {
T t1 = new T(true);
T t2 = new T(false);
t1.start();
t2.start();
}
}
class T extends Thread {
static Object o1 = new Object();
static Object o2 = new Object();
boolean flag;
public T(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
synchronized (o1) {
System.out.println(Thread.currentThread().getName()+"进入1");
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入2");
}
}
}
else {
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入3");
synchronized (o1) {
System.out.println(Thread.currentThread().getName()+"进入4");
}
}
}
}
}
浙公网安备 33010602011771号