-
进程 和 线程
进程就是指代码/算法在特定的数据集合上一次执行/运行的活动
也是系统进行资源分配和调度的基本单位。
线程则是进程的一个执行任务/单元,是进程中的一个实体。
一个进程中至少有一个线程,
进程中的多个线程是共享进程的资源的 -
操作系统资源分配和调度
操作系统在分配资源时是把资源分配给进程的,
但CPU资源比较特殊,是分派到线程级别的,
因为真正占用CPU运行的是线程,
将CPU的使用时间,划分为一个一个的时间片,
根据时间片调度分派给线程,只有线程获得CPU的时间片,
才可占用CPU运行代码。
假设CPU是单核的,同一个时间点,只有一个线程在运行。
细节微观的看,线程是顺序执行;
从人类角度宏观的看,是并行的:听歌、写文档等
- 进程的内存空间
进程中有多个线程,多个线程共享进程中的堆和方法区资源,
同时每个线程有自己的栈和程序计数器。
栈空间,用于存放线程执行中的局部变量,
这些局部变量,是当前线程私有的,其它线程也访问不了。
另外栈还用来存放线程的调用栈帧。
程序计数器,用来记录线程当前要执行的指令地址。
其实是为了记录让出CPU时间片时执行的地址
堆是进程中最大的一块内存空间,被进程中所有线程共享。
里面存放的是使用new创建的对象实例。
方法区,存放的是进程中要执行的代码,被线程共享
- Java中的线程
Java中使用Thread类,表示一个线程
JVM启动会开启一个进程java.exe
在jvm内部,运行java程序,执行多个线程
线程是一个执行任务单元;
Java中可以使用Thread类表示线程。
建立线程的方法:
1.
package day27_0324;
/**
* 1. 程序运行后,会产生进程,进程中至少有一个线程(即:主线程)
* 2. 线程是一个执行任务/执行单元
* 3. Java使用Thread类表示线程
* class Thread implements Runnable
* 4. JVM启动后,会在主线程中执行main方法中的代码;
* main线程中,创建启动了一个新的线程MyThread mt,不停地打印输出
* main线程接下来,继续向下执行代码,不停地打印输出
* 此时,在java进程中,有两个线程同时在运行!!
*
*/
public class ThreadDemo01 {
public static void main(String[] args) {
System.out.println("在主线程中,执行代码。"); //debug观察 Thread-main
MyThread mt = new MyThread();
mt.start(); //启动线程
// 在进程分配空间,等待CPU调度
// 当获得CPU的时间片时,才调用执行run()方法中的指令
//while(true) {
for (int i = 0; i < 30; i++) {
System.out.println("我是 main 主线程"); //debug观察两个线程同时运行
try {
Thread.sleep(300); //让线程休眠一会,300毫秒,慢下来便于观察
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("主线程代码执行完毕!");
}
}
/**
* 创建一个自定义的线程,定义类型继承Thread即可
* 将需要执行的任务,添加到类中run()方法中。
* 当run()方法中的任务代码执行完毕后,该线程就结束了!
*/
class MyThread extends Thread {
//run()方法没有返回值,也不能抛出异常
@Override
public void run() {
System.out.println("我是一个新的线程!");
System.out.println("当前对象:" + this);
//while(true) {
for (int i = 0; i < 20; i++) {
System.out.println("我是:" + this);
try {
Thread.sleep(300); //让线程休眠一会,300毫秒,慢下来便于观察
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("新的线程执行结束!");
}
}
package day27_0324;
/**
* 借助Runnable接口,创建任务,传入到Thread(runnable)构造器中创建线程
*
*/
public class ThreadDemo02 {
public static void main(String[] args) {
RunnableTask task = new RunnableTask();
Thread t = new Thread(task);
t.start();
System.out.println("主线程结束。"); //debug观察
}
}
// 创建一个可执行的任务
class RunnableTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是执行任务!");
}
}
3.(不常用)
package day27_0324;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/** 了解即可
* 1. JDK5.0中,引入了专门处理并发线程的包:
* java.util.concurrent
* 2. 在包中提供了新的可执行任务类:
* Callable接口,接口中的方法是:
* V call() throws Exception;
* 可返回结果,可抛出异常
* Runnable接口中的方法是:
* void run();
* 没有返回结果,不能抛出异常
*/
public class ThreadDemo03 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyCallable mc = new MyCallable(); //可被调用的对象,封装了计算逻辑
FutureTask<String> task = new FutureTask(mc); //创建将要被执行的任务
Thread t = new Thread(task);
t.start();
//获得线程执行的结果
String result = task.get();
System.out.println("线程执行的结果:" + result);
}
}
//创建一个可被调用的自定义类
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("在新线程中,开始执行计算任务...");
return "Smith";
}
}
线程相关小方法
```java
package day27_0324;
/**
* 线程中常用的API
*/
public class ThreadDemo04 {
public static void main(String[] args) {
//获得当前代码运行时,所在的线程
Thread currThread = Thread.currentThread();
System.out.println("运行当前代码的线程是:" + currThread.toString());
System.out.println("运行当前代码的线程的ID:" + currThread.getId());
System.out.println("运行当前代码的线程名是:" + currThread.getName());
System.out.println("运行当前代码的线程所在线程组的名字:"
+ currThread.getThreadGroup().getName());
System.out.println("运行当前代码的线程的优先级是:" +
currThread.getPriority());
System.out.println("运行当前代码的线程是守护线程吗:" +
currThread.isDaemon());
// 使用匿名内部类写法,创建一个线程对象
Thread t = new Thread() {
@Override
public void run() {
//获得当前代码运行时,所在的线程
Thread currThread = Thread.currentThread();
System.out.println("运行当前代码的线程是:" + currThread.toString());
System.out.println("运行当前代码的线程的ID:" + currThread.getId());
System.out.println("运行当前代码的线程名是:" + currThread.getName());
System.out.println("运行当前代码的线程所在线程组的名字:" + currThread.getThreadGroup().getName());
System.out.println("运行当前代码的线程的优先级是:" + currThread.getPriority());
System.out.println("运行当前代码的线程是守护线程吗:" + currThread.isDaemon());
}
};
t.start();
//再创建一个线程
new Thread(new Runnable() {
@Override
public void run() {
//获得当前代码运行时,所在的线程
Thread currThread = Thread.currentThread();
System.out.println("运行当前代码的线程是:" + currThread.toString());
System.out.println("运行当前代码的线程的ID:" + currThread.getId());
System.out.println("运行当前代码的线程名是:" + currThread.getName());
System.out.println("运行当前代码的线程所在线程组的名字:" + currThread.getThreadGroup().getName());
System.out.println("运行当前代码的线程的优先级是:" + currThread.getPriority());
System.out.println("运行当前代码的线程是守护线程吗:" + currThread.isDaemon());
}
}, "第3个线程").start();
System.out.println("线程的状态:" + currThread.getState());
System.out.println("线程是活动的吗?" + currThread.isAlive());
}
}
线程优先级控制
```java
package day27_0324;
/**
* 线程的优先级
* 1. 线程执行的前后顺序,是由多种因素决定的
* 项目实战时,不要去设置线程的优先级
* 2. 线程被分配时间片的时机,以及时间的长短,
* 由系统调度来分配决定的,代码无法直接干涉
* 3. 线程优先级,默认是:5
* 线程优先级从小到大是:1~10
*/
public class ThreadDemo05 {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread());
}
}
}, "优先级为1的线程,最低优先级");
t1.setPriority(1);
Thread t5 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread());
}
}
}, "优先级为5的线程");
Thread t10 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread());
}
}
}, "优先级为10的线程,最高优先级");
t10.setPriority(10);
t1.start();
t5.start();
t10.start();
}
}