目标
-
线程的概念
-
线程和进程的区别
-
串行、并行和并发的概念
-
-
线程的实现
-
线程的生命周期
-
线程的常用方法
线程的概念
程序和进程的区别
程序是静态的,进程是动态的,程序是存储在某种介质上的二进制代码,进程对应了程序的执行过程,系统不需要为一个不执行的程序创建进程,一旦进程被创建,就处于不断变化的动态过程中,对应了一个不断变化的上下文环境。
程序是永久的,进程是暂时存在的。程序的永久性是相对于进程而言的,只要不去删除它,它可以永久的存储在介质当中。
进程与线程的区别
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行 (3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源. (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
串行,并发和并行
-
串行 多个指令从上到下依次执行,
-
并发 每个线程会经行抢占时间片,所以会有来回切换的效果 但不是同时进行,没有时间安排会是等待的状态
-
并行 多个cpu内核同时执行多个线程,相互不影响且同时进行
线程的实现
java四种实现线程的方式
-
继承Thread类
-
实现Runnable接口
-
实现Callable接口
-
使用线程池
继承Thread类
-
继承Thread类
-
重写run方法
-
调用start启动线程
案例实现1
设计两个线程,一个线程负责打印1~100以内所有的偶数;然后,另外一个线程负责打印1~100以内所有的奇数。
class Thread1 extends Thread{
public void run(){
for (int i = 0; i <=100 ; i+=2) {
System.out.println(Thread2.currentThread().getName()+"奇数"+i);
}
}
}
class Thread2 extends Thread{
public void run(){
for (int i = 0; i <=100 ; i+=2) {
System.out.println(Thread2.currentThread().getName()+"偶数"+i);
}
}
}
public class ZuoYe1 {
public static void main(String[] args) {
Thread1 t1=new Thread1();
Thread2 t2=new Thread2();
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
案例二
实现一个线程,用于扫描某个目录下的所有文本文件(包括:java、txt、html),并将文字内容打印出来。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class ZuoYe02 {
public static void main(String[] args) {
new Thread(() -> {
File file = new File("D:\\workspace03");
readFile(file);
}).start();
}
public static void readFile(File f) {
if (f.isDirectory()) {
File[] files = f.listFiles();
if (files != null) {
for (File file : files) {
readFile(file);
}
}
} else {
System.out.println(f.getName());
//读文件
try {
//得到文件
//得到文件读取的字符流
FileReader fileReader = new FileReader(f);
//得到带缓冲字符流
BufferedReader bufferedReader = new BufferedReader(fileReader);
String readLine = null;
while((readLine = bufferedReader.readLine()) != null){
System.out.println(readLine);
}
fileReader.close();
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
案例三
某人正在看电视连续剧,从第1~88集,看到第10集时,来了一个送快递的,收完快递后后,继续看电视。
public class ZuoYe03 {
public static void main(String[] args) {
new Thread(()->{
for (int i = 1; i <89 ; i++) {
System.out.println(Thread.currentThread().getName() + "===" + "看到了第" + i + "级");
try{
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i==10){
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "===" + "送快递的来了");
try{
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "===" + "快递拿完了");
}
});
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
案例四
-
多线程模拟龟兔赛跑:
乌龟和兔子进行1000米赛跑,兔子前进5米,乌龟只能前进1米。
但兔子每20米要休息500毫秒,而乌龟是每100米休息500毫秒。
谁先到终点就结束程序,并显示获胜方
public class ZuoYe04 {
public static void main(String[] args) {
Result r = new Result();
new Thread(() -> {
for (int i = 1; i <= 1000; i++) {
System.out.println("乌龟跑了" + i + "米");
try {
Thread.sleep(1);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if (i >= 1000) {
r.isWin = true;
System.out.println("乌龟胜利了" + i);
break;
}
if (i % 100 == 0) {
try {
System.out.println("乌龟在"+i+"米处开始休息");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(() -> {
int m = 0;
for (int j = 1; j <= 200; j++) {
if(r.isWin){
System.out.println("兔子跑了" + m + "米............");
break;
}
m += 5;
System.out.println("兔子跑了" + m + "米");
try {
Thread.sleep(1);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if (m >= 1000) {
System.out.println("兔子胜利了" + j);
}
if (m % 20 == 0) {
try {
System.out.println("兔子在"+j*5+"米处开始休息");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
class Result{
boolean isWin = false;
}
线程的生命周期
线程几种状态:
-
新建 NEW
-
准备/就绪 START
-
运行 RUNNING
-
阻塞 BLOCKING
-
死亡 DEAD
线程的常用方法
常用方法
方法 | 介绍 |
---|---|
start() | 启动 |
stop() | 停止(禁用,可能导致线程死锁等问题),停止线程可以让run执行结束 |
String getName() | 获得线程的名字 |
setName(String) | 设置线程名字 |
sleep(long) | 进入睡眠,毫秒 |
setPriority(int) | 设置线程的优先级(1~10从低到高)越高抢CPU几率更高 |
setDaemon(boolean) | 设置为后台线程 true ,后台线程是为其它线程服务的,如果没有其它线程存在,就自动死亡;使用案例:GC就是一种后台线程 |
join() | 线程的加入(合并)让其它线程先执行完,再执行自己的指令 |
个人总结
上述归纳算是步入线程学习的门槛,要想能够熟练运用还是得多敲多练,‘
书山有路勤为径,学海无涯苦作舟