线程的概念以及实际操作
学习目标:
快速了解线程基本操作,和一些面试题
学习内容:
例如: 1、 了解到线程的概念 2、 了解线程里的串行,并行,并发的区别 3、 线程的多种的实现方式 4、 实际操作线程的概念
什么是程序什么是进程?
- 进程是运作状态的中的程序,一个是程序里可以包含一个或者多个进程
- 程序是保存到磁盘上的代码或者一系列文件,比如是一个东西放在那里属于静态的概念。
进程与线程的区别
- 进程是程序执行相关资源(CPU、内存、磁盘等)分配的最小单元
进程之间是相互独立的,有自己的内存空间 - 线程是CPU资源分配的最小单元
进程包含一个或多个线程
线程需要的资源更少,可以看做是一种轻量级的进程
线程会共享进程中的内存,线程也有独立的空间(栈、程序计数器)
线程相互通信更加方便
串行,并发和并行
- 串行
多个指令从上到下依次执行, - 并发
每个线程会经行抢占时间片,所以会有来回切换的效果
但不是同时进行,没有时间安排会是等待的状态 - 并行
多个cpu内核同时执行多个线程,相互不影响且同时进行
线程的实现
java四种实现线程的方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 使用线程池
线程继承Thread类的代码演示
- 继承Thread类
- 重写run方法
- 调用start启动线程
/**
* 自定义线程类
*/
class MyThread extends Thread{
/**
* 执行指令
*/
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() +"执行了" + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//创建线程对象
MyThread myThread = new MyThread();
//启动线程
myThread.start();
//主线程执行
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() +"执行了" + i);
}
}
}
当中提及的run()跟start()还有一些区别
- run()没有启动新线程,是会在主线程中执行
- 如果想起用一个新的线程需要start()才能启动
实现Runnable接口
- 实现Runnable接口
- 实现run方法
- 创建实现Runnable接口的对象,传入Thread对象中
- 启动线程
/**
* 实现Runnable接口的类
*/
class MyRunnable implements Runnable{
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
}
}
}
public class RunnableDemo {
public static void main(String[] args) {
//创建Runnable对象,传入Thread对象
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
//启动线程
thread.start();
//匿名内部类
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
}
}
});
thread2.start();
//Lambda表达式
new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
}
}).start();
}
}
继承Thread和实现Runnable的区别
- 继承Thread类,不能继承其它的类,语法有限制
- 实现Runnable接口,可以继承其它类,语法没有限制
- Runnalbe接口强制要求实现run方法,不容易出现错误
推荐实现Runnable方式
实现Callable接口
实现Callable接口可以返回值,继承Thread类和Runnable不行
- 实现Callable接口,实现call方法
- 创建Callable对象,传入FutureTask对象
- 创建FutureTask对象,传入Thread对象
- 启动线程
- 调用get方法得到返回结果
/**
* 实现Callable接口
*/
class MyCallable implements Callable<Long> {
@Override
public Long call() throws Exception {
//模拟复杂运算
long sum = 0;
for(long i = 0;i < 1000000000L;i++){
sum += i;
}
return sum;
}
}
public class CallableDemo {
public static void main(String[] args) {
//创建Callable对象,传入FutureTask对象
FutureTask<Long> task = new FutureTask<>(new MyCallable());
//创建FutureTask对象到Thread对象中
Thread thread = new Thread(task);
//启动线程
thread.start();
System.out.println("-----等待结果-----");
//获得返回值
try {
System.out.println(task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
实际操作
这是本人写的入门小案例可以了解了解
乌龟和兔子进行1000米赛跑,兔子前进5米,乌龟只能前进1米。
但兔子每20米要休息500毫秒,而乌龟是每100米休息500毫秒。
谁先到终点就结束程序,并显示获胜方
public class demo {
public static void main(String[] args) {
new Thread(()->{
for (int i = 0; i <= 1000; i=i+5) {
System.out.println("兔子跑了"+i+"米");
if (i%20==0){
try {
Thread.sleep(500);
if (i==1000){
System.out.println("兔子胜利了!");
System.exit(0);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(()->{
for (int i = 0; i <= 1000; i++) {
System.out.println("乌龟跑了"+i+"米");
if (i%100==0){
try {
Thread.sleep(500);
if (i==1000){
System.out.println("乌龟胜利了!");
System.exit(0);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}