1、线程的创建和启动
- Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类来体现。
Thread类的特性
Thread():创建新的Thread对象
- Thread(String threadname):创建线程并指定线程实例名
- Thread(Runnabletarget):指定创建线程的目标对象,它实现了Runnable接口中的run方法
Thread(Runnable target, String name):创建新的Thread对象
3、API创建线程的两种方式
JDK1.5之前创建新执行线程有两种方法:
- 创建一个继承于Thread类的子类
- 重写Thread的run()方法 —-> 将此线程的方法声明在run()方法中
- 创建Thread的子类对象
- 通过此对象调用start() ```java package com.haiyang.java;
/**
- 多线程的创建 方式一: 继承于 Thread类
- 1、创建一个继承于Thread类的子类
- 2、重写Thread类的run()方法
- 3、创建Thread类的子类对象
- 4、通过此对象调用start() *
- 例子: 遍历100以内的所有偶数
*/
public class ThreadTest {
public static void main(String[] args) {
}//3、创建Thread子类的对象
MyThread myThread = new MyThread();
//4、调用start()方法
myThread.start();
} //1、创建一个继承Thread类的子类 class MyThread extends Thread{ //2、重写Thread类的run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(i);
}
}
}
}
<a name="BaQNW"></a>
### 3.1.1、Thread中常用的方法
- **start()**: 启动当前线程,调用当前线程的run()方法
- **run()**:通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
- **currentThread()**:静态方法,返回执行当前代码的线程
- **getName()**:获取当前线程的名字
- **setName()**:设置当前线程的名字
- **yield() **:释放当前cpu的执行权
- **join()**: 在线程a中调用线程b的join(),此时线程a就会进入阻塞状态,直到线程b完全执行完成以后,线程a才结束阻塞状态
- **stop()**: 已过时 当执行此方法时强制线程结束
- **sleep(long millitime) **: 让当前线程“睡眠"指定的millitime毫秒,在指定睡眠的时间内,当前线程处于阻塞状态
- **isAlive() **: 判断当前线程是否存活
<br />
```java
/**
*
* 测试 Thread中常用的方法
* 1、start(): 启动当前线程,调用当前线程的run()方法
* 2、run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
* 3、currentThread():静态方法,返回执行当前代码的线程
* 4、getName():获取当前线程的名字
* 5、setName():设置当前线程的名字
* 6、yield() :释放当前cpu的执行权
* 7、join(): 在线程a中调用线程b的join(),此时线程a就会进入阻塞状态,直到线程b完全执行完成以后,线程a才结束阻塞状态
* 8、stop(): 已过时 当执行此方法时强制线程结束
* 9、sleep(long millitime) : 让当前线程“睡眠"指定的millitime毫秒,在指定睡眠的时间内,当前线程处于阻塞状态
* 10、isAlive() : 判断当前线程是否存活
* @author 杨磊
* @create 2021-09-24 20:12
*/
public class ThreadMethodTest {
public static void main(String[] args) {
//通过构造器给线程取名
HelloThread ht = new HelloThread("Thread:1");
//ht.setName("线程1");
//给主线程命名
Thread.currentThread().setName("主线程");
ht.start();
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
//yield(); 释放线程的执行权
}
if (i == 20){
try {
ht.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class HelloThread extends Thread{
public HelloThread(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + i);
//yield(); 释放线程的执行权
}
}
}
3.1.2、线程的调度
- 调度策略
- 时间片
抢占式:高优先级的线程抢占CPU
Java的调度方法
MAX_PRIORITY:10 —->最高优先级
- MIN _PRIORITY:1 —->最低优先级
-
3.1.2.2、涉及到的方法
getPriority() :返回线程优先值
setPriority(intnewPriority) :改变线程的优先级
说明:
高优先级的线程要抢占低优先级线程cpu的执行权。
- 但是只是从概率上讲,高优先级的线程高概率的情况下被执行。
并不意味着只有当高优先级的线程执行完以后,低优先级的线程才会被执行。
3.2、创建多线程的方式二:
创建一个实现了Runnable接口的类
- 实现类去实现Runnable中的接口方法
- 创建实现类对象
- 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
- 通过Thread类的对象调用start() ```java package com.haiyang.java;
/**
- 创建多线程的方式二 : 实现Runnable接口
- 1、创建一个实现了Runnable接口的类
- 2、实现类去实现Runnable中的接口方法
- 3、创建实现类对象
- 4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
- 5、通过Thread类的对象调用start()
- @author 杨磊
- @create 2021-09-24 22:04
*/
//1、创建一个实现了Runnable接口的类
class MThread implements Runnable{
//2、实现类去实现Runnable中的接口方法
@Override
public void run() {
} } public class ThreadTest1 { public static void main(String[] args) {for (int i = 0; i < 100; i++) {
if (i % 2 == 0 ){
System.out.println(i);
}
}
} }//3、创建实现类对象
MThread mThread = new MThread();
//4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread th = new Thread(mThread);
//5、通过Thread类的对象调用start()
th.start();
Thread th2 = new Thread(mThread);
th2.start();
<a name="zJqqh"></a>
## 3.3、继承方式和实现方式的联系与区别
开发中:优先选择:实现Runnable接口的方式<br />原因:
- 实现的方式没有类的单继承性的局限性
- 实现的方式更适合来处理多个线程有共享数据的情况。
联系:public class Thread implements Runnable<br />相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中
<a name="pJWNH"></a>
# 4、补充:线程的分类
**Java中的线程分为两类:一种是守护线程,一种是用户线程。**
- 它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。
- 守护线程是用来服务用户线程的,通过在start()方法前调用**thread.setDaemon(true)**可以把一个用户线程变成一个守护线程。
- Java垃圾回收就是一个典型的守护线程
- 若JVM中都是守护线程,当前JVM将退出。
- 形象理解:兔死狗烹,鸟尽弓藏
<a name="s3DG4"></a>
# 练习1
```java
/**
* 例子: 创建三个窗口去买票,总票数为100张
* @author 杨磊
* @create 2021-09-24 21:36
*/
class Window extends Thread{
private static int ticket = 100;
@Override
public void run() {
while (true){
if (ticket > 0){
System.out.println(getName() + "卖票,票号为:" + ticket);
ticket--;
}else {
System.out.println("不好意思,已经没有票了");
break;
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window w1 = new Window();
Window w2 = new Window();
Window w3 = new Window();
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}