系统编程 - 多线程编程
1. Unix操作系统:
第一款多任务多用户操作系统
现代操作系统之父
注意: 在多核CPU诞生之前(单核CPU下),所有的多任务本质都是一种伪多任务。(并没 有真正的实现多任务,只是来回切换运行,cpu速度很快,人肉眼感受不到)
多核CPU下,就可以实现真正意义上的多任务!!
2. 并发:多个任务(进程)抢占少量资源
并行:每个资源有一个独立cpu,之间形成并行
多核下才能有并行,单核只有并发
3. 让每个任务得到合理运行时间,防止一个任务持续抢占资源 和 先后顺序问题:
时间片:每一个任务每次在CPU中占有的时间
优先级别调度:任务有先后顺序问题,核心软件需要先运行(是为其他服务的)
注意:操作底层的多任务使用的就是时间片轮换机制,配合优先级别调度完成。(多核也一样,核再多也不太可能让每一个任务都单独分配到cpu)

首先看优先级别(也会根据重要性分配时间片) 。当每次结束后,优先级别-1,和其他任务一起再进行抢
4. 多任务:
多进程编程
多线程编程
协程编程
5. 多线程编程:
java自身提供了四种创建多线程的方案:
jdk5之前
1、继承Thread
2、实现Runable接口
jdk5之后
3、实现Callable接口
4、线程池实现多线程
推荐使用第2,3 种,不太推荐第1种。因为java是单继承机制,一旦某个类继承了一个类就不能继承其他类
而接口可以多继承
某个类继承了线程类,这个类就会自动的成为一个线程类
单线程情况下,没有办法直接让多个任务同时执行,下面的代码唱歌输出结束后才会输出跳舞
- package com.openlab.multithreading;
-
- public class TestIdea {
- public static void main(String[] args) {
- // 单线程情况下,没有办法直接让多个任务同时执行
- singe();
- dance();
-
- }
-
- public static void singe() {
- for (int i = 0; i < 100; i++) {
- System.out.println("我开始唱歌了——"+ i);
- }
- }
-
- public static void dance() {
- for (int i = 0; i < 100; i++) {
- System.out.println("我开始跳舞了——"+ i);
- }
- }
- }
继承Thread:
若对象调用方法的话还是先子线程,再主线程,还是不对,和之前一样
需要调用start()方法
- package Testthread;
-
- public class TestThread {
- public static void main(String[] args) {
- MyThread01 thread = new MyThread01();
- thread.run();
-
- for (int i = 0; i < 10000; i++) {
- System.out.println("主线程正在运行");
- }
-
-
- }
- }
-
-
- class MyThread01 extends Thread{
- @Override
- public void run() {
- for (int i = 0; i < 10000; i++) {
- System.out.println("子线程正在运行");
- }
- }
- }
调用start()方法:
注意:main函数也是线程,是主线程
- package Testthread;
-
- public class TestThread {
- public static void main(String[] args) {
- MyThread01 thread = new MyThread01();
-
- //调用start方法
- thread.start();
-
- for (int i = 0; i < 10000; i++) {
- System.out.println("主线程正在运行");
- }
-
-
- }
- }
-
-
- class MyThread01 extends Thread{
- @Override
- public void run() {
- for (int i = 0; i < 10000; i++) {
- System.out.println("子线程正在运行");
- }
- }
- }
结果会子线程、主线程交替执行,结果不可控
Runable接口只有一个方法run(),没有start()方法
但是Thread有个构造方法可以传入一个Runable对象,我们可以由此构建


- package Testthread;
-
- public class TestRunnable {
-
- public static void main(String[] args) {
- MyThread02 thread01 = new MyThread02();
- MyThread02 thread02 = new MyThread02();
-
- // 使用Runnable接口实现的多线程类,该类的对象没有start方法
- // 所以启动线程对象,必须借助Thread类的构造函数
- new Thread(thread01).start();
- new Thread(thread02).start();
- }
- }
-
-
- class MyThread02 implements Runnable {
-
- @Override
- public void run() {
- for (int i = 0; i < 10000; i++) {
- //每个线程都是有名字的
- //可以利用Thread.currentThread()当前线程获取当前线程的名字
- System.out.println(Thread.currentThread().getName() + "子线程正在运行");
- }
- }
-
- }
Callable接口也只有一个方法call(),有返回值。
也没有start()方法,而且Thread也没有一个构造方法里面有Callable
启动对应的线程对象需要用Future
FutureTask是Future的子类
FutureTask继承了RunnableFuture
RunnableFuture继承了Runnable和Future
即RunnableFuture是Runnable的子类,那么FutureTask也是Runnable的子类,我们就可以使用FutureTask
利用多态,接口式编程




- package Testthread;
-
- import java.util.concurrent.Callable;
- import java.util.concurrent.Future;
- import java.util.concurrent.FutureTask;
-
- public class TestCallable {
- public static void main(String[] args) {
- MyThead03 thread03 = new MyThead03();
- FutureTask futureTask = new FutureTask(thread03);
- new Thread(futureTask).start();
-
- for (int i = 0; i < 10000; i++) {
- System.out.println(Thread.currentThread().getName() +"主线程开始运行");
- }
-
- }
- }
-
-
- class MyThead03 implements Callable
{ -
- int sum = 0;
- @Override
- public Integer call() throws Exception {
- for (int i = 0; i < 10000; i++) {
- sum += i;
- System.out.println("使用Callable接口创建的子线程"+ i);
- }
- return sum;
- }
- }
使用callable接口实现的多线程对象,最后能够得到线程方法返回的结果
即这个例子中的当前子线程结束,会返回一个结果
用get()方法拿到
- package com.openlab.multithreading;
-
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.FutureTask;
- import java.util.concurrent.RunnableFuture;
-
- public class TestCallable {
- public static void main(String[] args) {
- MyThread2 mt = new MyThread2();
- FutureTask futureTask = new FutureTask(mt);
- new Thread(futureTask).start();
-
-
- // 使用callable接口实现的多线程对象,最后能够得到线程方法返回的结果
- try {
- Integer res = (Integer) futureTask.get();
- System.out.println("线程方法返回的结果:" +res);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
-
- for (int i = 0; i < 10000; i++) {
- System.out.println(Thread.currentThread().getName() +"主线程开始运行");
- }
-
- }
- }
-
- class MyThread2 implements Callable
{ - @Override
- public Integer call() throws Exception {
- int sum = 0;
- for (int i = 0; i < 10000; i++) {
- sum += i;
- System.out.println("使用Callable接口创建的子线程"+ i);
- }
- return sum;
- }
- }

Thread的run()和start()区别:
run()是一个线程方法,该方法里面的代码是线程直接执行时需要执行的代码,但是不能直接调用,否则就是普通方法了。
需要start()去启动run()方法
getName //获取当前线程名称
getId //获取线程编号(每个线程一旦启动,编号是固定的)
PID,进程编号,操作系统为每一个进程分配的编号,也是唯一的
getPriority //获取线程的优先级。最小的优先级是1,最大是10
getState //获取线程状态,有六种状态
尚未启动(NEW),运行(RUNNABLE),阻塞(BLOCKED),等待(WAITING),具有 指定等待时间的某一等待线程的线程状态(TIMED_WAITING),终止(TERMINATED)
interrupt //线程中断,调用不会中断当前线程,表示要抛出一个中断信号
stop //早在jdk2.0就已过时,因为是暴力终止线程,应该根据自己的逻辑代码去终止
isAlive //判断线程是否活着
join //阻塞当前线程,不再成并发效果,其他线程不会跟此线程进行资源抢夺,让当前线 程执行结束。
setDaemon //若为true表示将当前线程设为守护线程。
守护线程依赖于一个线程存在,这个线程启动就启动,关闭就关闭
- package Testthread;
-
- public class TestThread {
- public static void main(String[] args) {
- MyThread myThread = new MyThread();
- myThread.start();
-
- for (int i = 0; i < 10000; i++) {
- System.out.println("主线程正在运行");
- }
-
-
- }
- }
-
-
- class MyThread extends Thread{
- @Override
- public void run() {
- for (int i = 0; i < 10000; i++) {
- System.out.println("子线程正在运行");
- }
- }
- }
以下代码都是写在main线程中的
// 获取线程名称
System.out.println(myThread.getName());
myThread.setName("豪豪");
System.out.println(myThread.getName());

//获取线程编号
//没有setID
System.out.println(myThread.getId());
![]()
//获取线程的优先级
System.out.println(myThread.getPriority());
myThread.setPriority(6);
System.out.println(myThread.getPriority());
System.out.println(Thread.currentThread().getPriority());
System.out.println(myThread.isAlive());
![]()
myThread.join();

使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),毫秒结束后将会继续执行
- // java的线程类
- class MyThread extends Thread {
-
- @Override
- public void run() {
- // 要执行的代码写在这儿
- for (int i = 0; i < 100; i++) {
- if (i == 5) {
- try {
- // 让线程进入休眠状态
- Thread.sleep(20);//传的是毫秒数
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println(Thread.currentThread().getName() + "一个独立的子线程运行了" + i);
- }
- }
- }
我们用的是Thread的子类,所以我们使用的话需要写构造函数
主函数不能构造,所以主函数只能通过setName()
//主函数修改名字
Thread.currentThread().setName("主函数");

- package com.openlab.multithreading;
-
- public class TestThread {
- public static void main(String[] args) throws InterruptedException {
- MyThread myThread = new MyThread("张三");
- MyThread myThread02 = new MyThread("李四");
- }
-
- // java的线程类
- class MyThread extends Thread {
-
- public MyThread() {
- }
-
- public MyThread(String name) {
- super(name);
- }
-
- @Override
- public void run() {
- // 要执行的代码写在这儿
- for (int i = 0; i < 100; i++) {
- if (i == 5) {
- try {
- // 让线程进入休眠状态
- Thread.sleep(20);//传的是毫秒数
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println(Thread.currentThread().getName() + "一个独立的子线程运行了" + i);
- }
- }
- }
暗示当前线程放弃一次抢占。只是暗示,当前线程是自由的,它可以忽视这个暗示
