一、什么是线程?
1、进程的概念
- 进程是指可执行程序并存放在计算机存储器的一个指令序列,它是一个动态执行的过程。
- 有的软件只有一个进程,如记事本;有的软件是由多个进程组成的。
早期的进程是单任务的,只能运行一个程序,现在的操作系统是多任务的操作系统,多个程序可以同时运行。
2、什么是线程?
线程是比进程还要小的运行单位,一个进程包含多个线程。
- 比如一个程序是由很多行代码组成的,这些代码就可以分成很多块,放到线程中,分别执行。
- 线程相当于一个子程序
时间片的轮转:把CPU的执行时间分成很多的小块,每一小块的时间都是固定的,我们将这一小块的时间成为时间片;时间片的时间可以非常短,比如1ms,多个软件同时运行,多个软件分别获取时间片去处理,对于CPU来讲,这些软件都是轮流运行的,但是由于分别运行的时间间隔非常短,对于我们使用者而言是察觉不到的,可以认为这些软件是同时运行的。
二、线程的创建
1、创建线程的几种方式
- 创建一个Thread类,或者一个Thread子类的对象。
-
2、Thread类
Thread类是一个线程类,位于java.lang包下 | 构造方法 | 说明 | | —- | —- | | Thread() | 创建一个线程对象 | | Thread(String name) | 创建一个具有指定名称的线程对象 | | Thread(Runnable target) | 创建一个基于Runnable接口实现类的线程对象 | | Thread(Runnable target,String name) | 创建一个基于Runnable接口实现类,并且具有指定名称的线程对象 |
Thread类的常用方法 | 方法 | 说明 | | —- | —- | | public void run() | 线程相关的代码写在该方法中(线程体的代码),一般需要重写 | | public void start() | 启动线程的方法 | | public static void sleep(long m) | 线程休眠m毫秒的方法 | | public void join() | 优先执行调用join()方法的线程,抢占资源 |
通过继承Thread类创建线程 ```java class MyThread extends Thread { public MyThread(String name) {
super(name);
} @Override public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"正在运行"+i);
}
} }
public class ThreadTest { public static void main(String[] args) { MyThread mt1 = new MyThread(“线程1”); MyThread mt2 = new MyThread(“线程2”); mt1.start(); mt2.start();
}
}
<a name="DJpsv"></a>
#### 3、Runnable接口
- 只有一个方法`run()`
- Runnable是Java中用以实现线程的接口
- 任何实现线程功能的类都必须实现该接口,Thread类实际上是实现了Runnable接口的。
- 通过实现Runnable接口的方式创建,(为什么要实现Runnable接口?1、Java不支持多线程;2、不打算重写Thread类的其他方法)
```java
class PrintRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"正在运行"+i);
}
}
}
public class RunnableTest {
public static void main(String[] args) {
PrintRunnable printRunnable = new PrintRunnable();
Thread thread1 = new Thread(printRunnable,"线程1");
Thread thread3 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在运行" + i);
}
}, "线程3");
Thread thread2 = new Thread(printRunnable,"线程2");
thread1.start();
thread2.start();
thread3.start();
}
}
三、线程的状态和生命周期
1、线程的状态
- 新建(new) :当创建一个Thread类或Thread子类对象的时候
- 可运行(Runnable):当已经创建好的线程对象去调用
start()
f方法,这时候就进入了可运行状态,线程什么时候运行是由CPU来决定的,只有当线程获取到CPU的使用权的时候,它才能执行,所以线程调用start()
方法之后,只是进入一个可运行状态,也把这种状态叫做就绪状态。 - 正在运行(Running):处于可运行状态的线程,一旦获取了CPU的使用权,就可以立即进入正在运行状态。
- 阻塞(Blocked):当线程受到了一些干扰的时候,就会进入阻塞状态,也就是它不在执行。
-
2、线程的声明周期,即线程从创建到启动,直至运行结束这段时间。也就是以上五个状态之间的相互转换过程。
3、sleep方法的使用
Thread类中的方法
public static void sleep(long millis)
。- 休眠时间到了之后并不能让线程进入运行状态,只能进入一个可运行状态,可运行状态的线程只有获取带CPU的使用权之后,才能进入运行状态。
- 作用:在指定的毫秒数内让正在执行的线程休眠(暂停执行、阻塞)。
- 参数为休眠的时间,单位是毫秒。
作用:可以用作计时器(有误差)、定期发送数据等。
class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + "正在运行" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SleepTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread, "线程1");
thread1.start();
Thread thread2 = new Thread(myThread, "线程2");
thread2.start();
}
}
4、Join方法应用
Thread类的方法:
public final void join()
/public final void join(long millis)
- 作用:等待调用该方法的线程结束后才能执行/等待该线程终止的最长时间为millis毫秒
```java
class MyThread implements Runnable {
@Override
public void run() {
} }for (int i = 0; i < 500; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行" + i);
}
public class JoinDemo { public static void main(String[] args) { Thread thread = new Thread(new MyThread(), “我的线程1”); thread.start(); try { thread.join(2); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 30; i++) { System.out.println(“主线程运行第” + i + “次”); } } }
<a name="w5hRI"></a>
## 四、线程的调度
<a name="eRTI3"></a>
#### 1、线程优先级
- Java为线程优先级提供了10个优先级
- 优先级可以用整数1-10表示,数字越大,表示有限级别越高;超过范围会抛出异常
- 主线程默认优先级为5
- 还可以用优先级常量表示
- MAX_PRIORITY:线程的最高优先级10
- MIN_PRIORITY:线程的最低优先级1
- NORM_PRIORITY:线程的默认优先级5
- 优先级相关的方法
| 方法 | 说明 |
| --- | --- |
| publc int getPriority() | 获取线程优先级的方法 |
| public void setPriority(int newPriority) | 设置线程优先级的方法 |
```java
class MyThread extends Thread {
private String name;
public MyThread(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("线程" + name + "正在运行" + i);
}
}
}
public class PriorityDemo {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyThread("1"));
Thread thread2 = new Thread(new MyThread("2"));
thread1.setPriority(10);
thread2.setPriority(1);
System.out.println("thread1 = " + thread1.getPriority());
System.out.println("thread2 = " + thread2.getPriority());
thread1.start();
thread2.start();
/* //获取主线程的优先级
int priority = Thread.currentThread().getPriority();
System.out.println("主线程的优先级:priority = " + priority);*/
/* for (int i = 0; i < 15; i++) {
System.out.println("主线程正在运行"+i);
}*/
}
}
2、多线程运行问题
- 各个线程 是通过竞争CPU时间而获得运行机会的
- 各线程什么时候得到CPU时间,占用多久,是不可预测的。
- 为了保证在存款和取款的时候,不宜徐其他线程对账户余额进行操作;需要将Bank对象进行锁定,使用synchronized实现,可以实现共享对象在同一个时刻只能被一个线程所访问。
synchronized关键字用在
问题:账户余额不够了怎么办?等待存入足够的钱后处理?
wait()
方法:中断线程的执行,使线程等待(阻塞状态)notify()
方法:唤醒等待的某一个线程,使其结束等待notifyAll()
:唤醒所有处于等待状态的线程,使它们结束等待