线程的基本概念
- 一个线程是一个程序内部的顺序控制流。
- 线程和进程
- 每个进程都有独立的代码和数据空间(进程上下文),进程切换的开销大。
- 线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小
- 多进程:在操作系统中,能同时运行多个任务(程序)。
- 多线程:在同一应用程序中,有多个顺序流同时执行。
线程的概念模型
- 虚拟的CPU,封装在Java.lang.Thread类中。
- CPU所执行的代码,传递给Thread类。
- CPU所处理的数据,传递给Thread类。
线程体
-
Java的线程是通过Java.lang.Thread类来现实的。
-
每个线程都是通过某个特定Thread对象的方法run()来完成其操作的,方法run()称为线程体。
构建线程的两种方法
- 定义一个线程类,它继承类Thread并重写其中的run()方法。
class MyThread extends Thread{
@Override
public void run(){
// 业务代码
}
}
public class ThreadTester{
public static void main(String[] args) {
MyThread thread = new MyThread();
// 开启线程,将自动进入run()方法;
thread.start();
}
}
-
提供一个实现接口Runnable的类作为线程的目标对象,在初始化一个Thread类或其子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体run()。
- public Thread(ThreadGroup group,Runnable target,String name);
class MyThread implements Runnable{ public void run(){ // 业务代码 } } public class ThreadTester{ public static void main(String[] args) { MyThread thread = new MyThread(); // 开启线程,将自动进入run()方法; new Thread(thread).start(); } }
两种线程构建方法的比较
- 使用Runnable接口 可以将CPU,代码和数据分开,形成清晰的模型;还可以继承其他类
- 直接继承Thread类 编写简单,直接继承,重写run方法,不能在继承其他类
线程的休眠
/**
* 线程休眠的原因:就是让其他线程得到执行的机会
*/
public void run(){
Thread.sleep(1000); // 休眠1000毫秒
// 业务代码
}
Thread类-常用API
- public Thread()
- 构造一个新的线程对象
- public Thread(Runnable target)
- 构造一个新的线程对象,以一个实现Runnable接口的类的对象为参数
- public Thread(String name)
- 构造一个新的线程对象,并同时指定线程名
- public static Thread currentThread()
- 返回当前正在运行的线程对象
- public static void yield()
- 使当前线程对象暂停,允许别的线程开始运行
- public static void sleep(long millis)
- 使当前线程暂停运行指定毫秒数,但此线程并不失去以获得的锁
- public void start()
- 启动线程,JVM将调用此线程的run()方法,结果是将同时运行两个线程,当前线程和执行run()方法的线程
- public void run()
- Thread的子类应该重写此方法,内容应为该线程应执行的任务。
- public final void stop()
- 停止线程运行,释放该线程占用的对象锁
- public void interrupt()
- 中断此线程
- public final void join() / join(long millis)
- 如果此前启动了线程A,调用join方法将等待 (指定毫秒数或) 线程A死亡才能继续执行当前线程
- public final void setPriority(int newPriority)
- 设置线程优先级
- public final void setDaemon(Boolean on)
- 设置是否为后台线程,如果是当前运行线程均为后台线程则JVM停止运行。这个方法必须在start()方法前使用
- public final void checkAccess()
- 判断当前线程是否有权力修改调用此方法线程
- public void setName(String name)
- 更改本线程的名称为指定的参数
- public final boolean isAlive()
- 测试线程是否处于活动状态,如果线程被启动并且没有死亡则返回true
线程内部的数据共享
/**
* 用三个线程模拟三个售票口,总共售出200张票
* */
public class SellTicketsTester {
public static void main(String[] args) {
SellTickets t = new SellTickets();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
class SellTickets implements Runnable{
// 总票数(线程共享数据)
private int tickets = 200;
public void run() {
while (tickets > 0){
System.out.println(Thread.currentThread().getName() + "剩余总数" + --tickets);
}
}
}
/** output:
* Thread-0剩余总数199
* Thread-1剩余总数198
* ...
* Thread-0剩余总数3
* Thread-0剩余总数2
* Thread-0剩余总数1
* Thread-0剩余总数0
*/