多线程(1)
进程和线程
进程:正在运行的程序
- 是系统进行资源分配和调用的独立单位
- 每一个进程都有他自己的内存空间和系统资源进程指当前正在执行的程序,代表一个应用程序在内存中的执行区域
线程:是进程中单个顺序控制流,是一条执行路径
- 是进程中的一个执行控制单元,执行路径。
- 单线程:一个进程如果只有一条执行路径,则称为单线程
- 多线程:一个进程如果有多个执行路径,则称为多线程
注意:
进程只是负责开辟内存空间的,线程才是负责执行代码逻辑的执行单元。
通过Thread类实现多线程
实现多线程:
方式一:继承Thread类
-
定义一个类继承Thread类
-
在类中重写run方法
-
创建类的对象
-
启动线程
为什么要重写run方法?
因为run方法用来封装被线程执行的代码
run和start的区别?
-
run():封装线程执行的代码,直接调用,相当于普通方法
-
start():启动线程,然后由JVM调用此线程的run()方法
MyThread.java
package javaDemo.ThreadDemo.Demo01;
//1.创建一个Thread类的子类
public class MyThread extends Thread{
//2.在Thread类的子类中重写thread类中的run方法,设置线程任务(开启线程要做什么?)
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run"+i);
}
}
}
test01.java
package javaDemo.ThreadDemo.Demo01;
public class test01 {
public static void main(String[] args) {
// 3.创建Thread类的子类对象
MyThread mt = new MyThread();
// 调用thread类中的方法start方法,开启新的线程,执行run方法
mt.start();
// 主线程会继续执行主方法中的代码
for (int i = 0; i < 20; i++) {
System.out.println("main"+i);
}
}
}
线程的随机性
在某一个时刻,CPU只能执行一个程序,所以多个程序同时执行并不是真正的同时执行。其实就是CPU在做着快速的切换完成的。只是你感觉上同时而已。这样就造成打印的数据不规律。
搞个图:
设置和获取线程的名称
Thread中设置和获取线程名称的方法
- void SetName(String name):将线程的名称设置为name
-String getName():返回次线程的名称
-Thread(String name):构造函数,线程对象一建立就可以指定名称
-static Thread currentThread():获取当前线程对象
MyThread.java
package javaDemo.ThreadDemo.SetCatchName;
import java.sql.SQLOutput;
/*
获取线程的名称:
1.使用Thread类中的方法getName()
String getName()
返回该线程的名称
2.可以先获取到当前正在执行的线程,使用线程中的方法getName()获取线程的名称
static Thread currentThread()返回对当前正在执行的线程对象的引用。
*/
public class MyThread extends Thread{
// 重写Thread类中的run方法,设置线程任务
@Override
public void run() {
// 方法一获取线程名称,图1
// String name=getName();
// System.out.println(name);
// 方法二获取,图2
// Thread t = Thread.currentThread();
System.out.println(t);//Thread[Thread-0,5,main]
System.out.println(t.getName());
// 简单写:,图3
System.out.println(Thread.currentThread().getName());
}
}
Test.java
package javaDemo.ThreadDemo.SetCatchName;
/*
线程的名称:
主线程:main
新线程:Thread-0,Thread-1,Thread-2
*/
public class Test {
public static void main(String[] args) {
// 创建Thread类的子类对象
MyThread mt = new MyThread();
// 调用start方法,开启新线程,执行run方法
mt.start();
new MyThread().start();
new MyThread().start();
// 链式编程,图4
System.out.println(Thread.currentThread().getName());
}
}
图1:方法①
图2:方法②
图3:方法②简单写
图4:链式编程求主线程
线程调度
线程有两种调度模式
分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间+
抢占调度模型:优先让优先级高的线程使用CPU,如果线程优先级相同,会进行随机,优先级高的线程获取CPU的时间相对较多
Java使用的是抢占模式
Thread设置获取线程优先级的方法
int getPriority() | 返回此线程的优先级 |
void setPriority() | 更改此线程的优先级 |
注意:
线程默认优先级为5,最大优先级为10,最小优先级为1
优先级高仅仅表示了抢占CPU的概率大,在次数多的时候效果明显
Mythread.java
package Day22.priorityDemo;
public class Mythread extends Thread{
@Override
public void run() {
for (int i = 0; i < 15; i++) {
System.out.println(getName()+i);
}
}
}
anotherThread.java
package Day22.priorityDemo;
public class anotherThread extends Thread{
@Override
public void run() {
for (int i = 0; i <15 ; i++) {
System.out.println(getName()+i);
}
}
}
test.java
package Day22.priorityDemo;
public class test {
public static void main(String[] args) {
Mythread mt = new Mythread();
mt.setName("mt");
anotherThread at = new anotherThread();
at.setName("at");
mt.start();
at.start();
mt.setPriority(5);
at.setPriority(10);
}
}
线程控制
void sleep(long millis) | 使当前正在执行的线程暂停指定的毫秒数 |
void join() | 等待这个线程的死亡 |
void setDaemon(boolean on) | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出 |
爬山案例:
Oldman.java
package Day22.sleepANDjoin;
//老年人一次爬100米。休息10秒
public class Oldman extends Thread {
@Override
public void run() {
for (int i = 100; i <=1000 ;i+=100) {
System.out.println(getName()+"----"+i);
if (i==1000){
System.out.print("Oldman爬完了");
}
try {
sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Youngman.java
package Day22.sleepANDjoin;
//年轻人一次爬500米。休息5秒
public class Youngman extends Thread {
@Override
public void run() {
for (int i = 500; i <=1000 ; i+=500) {
System.out.println(getName()+"----"+i);
if (i==1000){
System.out.println("Youngman爬完了");
}
try {
Youngman.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Test.java
package Day22.sleepANDjoin;
//爬山
public class Test {
public static void main(String[] args) {
Oldman oldman = new Oldman();
oldman.setName("oldman");//设置线程名字
Youngman youngman = new Youngman();
youngman.setName("youngman");//设置线程名字
oldman.start();
youngman.start();
}
}
结果:
多线程的生命周期
通过Runnable实现多线程
实现多线程:
方式二:实现Runnable接口
- 定义一个类实现Runnable类
- 在类中重写run方法
- 创建类的对象
- 创建Thread对象,把类的对象作为构造方法的参数
- 启动线程
多线程的实现方式:
- 继承Thread类
- 实现Runnable接口
实现Runnable的好处
- 避免了Java的单继承的局限性
- 适合多个线程去同时处理同一个资源
RunnableImPl.java
package Day22.Runnable.demo2;
// 1.创建一个Runnable接口的实现类
public class RunnableImPl implements Runnable{
// 2.在实现类中重写Runnable接口的run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
}
}
RunnableDemo.java
package Day22.Runnable.demo2;
/* 创建多线程程序的第二种方法:实现runnable接口
Java.lang.Runnable
Runnable接口应该由那些打算通过某一线程执行其实例的类来实现,类必须定义一个称为run的无参方法
java.lang.Thread类的构造方法
Thread(Runnable target)分配新的Thread对象
Thread(Runnable target,String name)分配新的Thread对象
实现步骤:
1.创建一个Runnable接口的实现类
2.在实现类中重写Runnable接口的run方法,设置线程任务
3.创建runnab接口的实现类对象
4.创建Thread类对象,构造方法中传递的Runnable接口的实现类
5.调用Thread类中的start方法,开启新的线程执行run方法
*/
public class RunnableDemo {
public static void main(String[] args) {
// 3.创建runnab接口的实现类对象
RunnableImPl run = new RunnableImPl();
// 4.创建Thread类对象,构造方法中传递的Runnable接口的实现类
Thread t = new Thread(run);
t.start();
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
}
}
|
|
|
|
|