一、介绍
多线程
三高: 高可用 高性能 高并发
thread 类
线程是程序中执行的线程。 Java虚拟机允许应用程序同时运行多个执行线程。
多线程:
多任务执行,多条路径可以执行
多线程的优点:
提高效率
进程 与 线程 之间的区别:
进程: 系统中的应用程序,一个进程之间包含1~n个线程,进程具有自己的资源,内存空间,进程是资源分配的最小单位
线程: 一个程序中的顺序流,多个线程共享一个进程的资源和数据空间,每一个线程具有自己的程序计数器,线程是cpu调度的最小单位
学习的目标:
1.线程的创建于开启 *****
2.线程的状态 : 新生 就绪 运行 阻塞 终止
3.线程安全 *****
4.线程通信 wait() notify()
1.线程的创建有多种方法
线程的创建:
1.继承Thread,重写run()方法,定义线程体 + start()
2.实现Runnable接口,重写run()方法 + start() --> 推荐
3.juc包下Callable接口,重写call()方法
代码解析1
public class Class01_Thread01 extends Thread {
public static void main(String[] args) {
//创建线程
Class01_Thread01 th = new Class01_Thread01();
//开启多线程
th.start();
//主方法执行的代码
for (int i=1;i<=100;i++){
System.out.println("一遍讲课...");
try {
th.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
for (int i=0;i<=100;i++){
System.out.println("一边喝水...");
}
}
}
代码解析2
/*
实现Runnable接口,重写run方法 + start()
1.类是单继承,接口多实现
2.可以实现资源共享
*/
public class Class02_Thread02 implements Runnable{
public static void main(String[] args) {
//创建线程对象
Thread th = new Thread(new Class02_Thread02());
//开启多线程
th.start();
for (int i=1;i<=10;i++){
System.out.println("一边陪女朋友");
try {
th.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
代码解析3
/*
* 实现Callable,重写call(),在方法内部定义线程体 --> 了解
* 1.call可以抛出异常
* 2.可以定义返回值
*/
public class Class06_Racer implements Callable<Integer> {
//赢的参赛者名字
private String winner = null;
public static void main(String[] args) throws ExecutionException, InterruptedException {
//一场比赛
Class06_Racer racer = new Class06_Racer();
//1.创建执行服务
ExecutorService server = Executors.newFixedThreadPool(2);
//2.提交任务
Future<Integer> future1 = server.submit(racer);
Future<Integer> future2 = server.submit(racer);
//3.获取结果
System.out.println(future1.get());
System.out.println(future2.get());
}
@Override
public Integer call() {
for(int steps=1;steps<=100;steps++){
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在第"+steps+"步...");
//判断是否为兔子每跑十步休息一下 100毫秒
if("pool-1-thread-1".equals(Thread.currentThread().getName()) && steps%10==0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//游戏是否结束,是否有参赛者赢了
if(checkOver(steps)){
return steps;
}
}
return null;
}
/**
* 检查游戏是否已经结束
* @param steps 当前参赛者的步数
* @return 是否结束
* true-->结束
* false-->不结束
*/
private boolean checkOver(int steps) {
if (winner!=null){
return true;
}
if (steps==100){
winner=Thread.currentThread().getName();
return true;
}
return false;
}
}
附:其他线程体方式
/*
* 其他定义线程体的方式
*/
/*
线程:
用户线程
守护线程
守护线程就是用来守护用户线程,当程序中所有的用户线程全部执行完毕,守护线程会直接结束
setDaeson(true) 设置守护线程
isDaeson() 判断线程是否为守护线程
现在所创建的线程默认都是用户线程
垃圾回收机制典型的守护线程
*/
public class Class07_Thread{
public static void main(String[] args) {
Thread th = new Thread(()->{
int i = 1;
while(true){
System.out.println("守护线程"+i++);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
/*设置为守护线程*/
th.setDaemon(true);
//开启线程
th.start();
for(int i=100;i<=110;i++){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
System.out.println("主线程执行完毕");
}
}
2.利用多线程的简单例题
1)模拟12306购票
/*
模拟12306购票
100张票 3个人买完
共享的资源: 100张张票
多线程: 4个线程 1个主线程 3个线程买票
注意: 多线程同时操作同一份资源就有可能出现线程不安全问题
*/
public class Class03_Web12306 implements Runnable{
int tickets = 100; //100张票
@Override
public void run() {
//重复买票
while (true){
//判断票是否卖完
if (tickets<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"正在买第"+tickets-- +"张票");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Class03_Web12306 web = new Class03_Web12306();
//创建线程
Thread th1 = new Thread(web,"石潘超");
Thread th2 = new Thread(web,"郑达");
Thread th3 = new Thread(web,"刘本军");
//开启线程
th1.start();
th2.start();
th3.start();
}
}
2)网络上下载资源
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.TreeMap;
/*
网络资源下载
*/
public class Class04_TestWebDownloader {
public static void main(String[] args) {
Thread th1 = new Thread(new Downloader("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png","src/baidu.png"));
Thread th2 = new Thread(new Downloader("https://img13.360buyimg.com/pop/s590x470_jfs/t1/191473/22/13064/97981/60efcd7fEde609b1a/8640695d031c2e4f.jpg","src/jd1.jpg"));
Thread th3 = new Thread(new Downloader("https://imgcps.jd.com/ling4/3548676/6Ziy6Zuo6Ziy5rGb5b-F5aSH/54iG5qy-5L2O6IezOS455YWD/p-5bd8253082acdd181d02fa42/4f1be342/cr/s/q.jpg","src/jd2.jpg"));
//启动线程
th1.start();
th2.start();
th3.start();
}
}
/*
网络资源下载的JAVABEAN
*/
class Downloader implements Runnable{
private String url;
private String pathName;
public Downloader(String url, String pathName) {
this.url = url;
this.pathName = pathName;
}
@Override
public void run() {
WebDownloader.down(url,pathName);
}
}
//定义网络下载工具类
class WebDownloader{
//网络资源下载步骤
public static void down(String url,String pathName){
try {
FileUtils.copyURLToFile(new URL(url),new File(pathName));
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、多线程的各种特点
1.线程的多种状态
/*
线程的状态:
新生状态 : new Thread(),当前线程处于新生状态
就绪状态 : start(),这个线程进入就绪状态,线程准备好可以被cpu调度,会进入到就绪队列,等待cpu的调度
运行状态 : 当cpu调度到这个线程,线程进入到运行状态开始执行
阻塞状态 : 当程序无法正常执行(进入阻塞状态的多种方式...)
终止状态 : 线程结束
1.一个线程一旦终止,无法恢复
2.一个线程如果进入阻塞状态,阻塞接触会直接恢复到就绪状态
进入到阻塞状态的几种方式 :
1. sleep()
2. join()
3. wait()
4. IO
进入线程就绪状态的方式:
1. start()
2. yield()
3. 线程切换
4. 阻塞接触
进入终止状态的方式:
1.stop 已经过时,不推荐使用 2.正常之间完毕 3.添加标识判断 --> 推荐
sleep(ms) : 1s = 1000ms
线程休眠|睡眠
会进入到阻塞状态,当指定的ms数结束,线程会恢复到就绪状态
抱着资源睡觉
让出cpu的资源
抱着是指对象的资源|锁
作用 :
1) 模拟网络延迟
2) 方法问题的可能性
练习: 模拟倒计时 10 9 8 7 ... 1
*/
2.分类
1)礼让线程
/*
yield 礼让线程 高风亮节
当一个线程调用yield,让出cpu的资源,进入到就绪状态
静态方法
*/
public class Class002_Yield implements Runnable{
public static void main(String[] args) {
new Thread(new Class002_Yield(),"A").start();
new Thread(new Class002_Yield(),"B").start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始了");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"结束了");
}
}
2)插队线程
/*
join() 插队线程
join(ms) 插队指定的ms数
成员方法join,线程对象.join() 当前线程对象插队
注意: 先就绪,后插队
*/
public class Class03_Join {
public static void main(String[] args) {
new Thread(new Father()).start();
}
}
//父亲线程
class Father implements Runnable{
@Override
public void run() {
System.out.println("想喝酒了...");
System.out.println("给儿子钱,让他去买啤酒...");
//创建线程
Thread th = new Thread(new Son());
//开启线程
th.start();
try {
th.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("爸爸接过啤酒,喝了一口...");
System.out.println("爸爸把剩下的钱给了儿子...");
}
}
//儿子线程
class Son implements Runnable{
@Override
public void run() {
System.out.println("接过钱,去买啤酒...");
System.out.println("路上看见一家游戏厅,进去玩10s....");
for (int i=1;i<=10;i++){
System.out.println(i+"s过去了...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("赶紧去买啤酒..");
System.out.println("把啤酒递给老爸,然后把钱给他...");
}
}
3)中断标识
/*
void interrupt() 为线程添加一个中断标识
boolean isInterrupted() 测试此线程是否已被中断,是否已经调用过 interrupt()方法添加中断标识,是->true 不是->false
static boolean interrupted() 测试当前线程是否已被中断, 是否已经调用过 interrupt()方法添加中断标识,是->true 不是->false,同时会复位标识
注意: 一个线程如果进入终止状态,线程的中断标识会复位
sleep--> InterruptedException - 如果有任何线程中断了当前线程。 抛出此异常时,将清除当前线程的中断状态 。
*/
public class Class04_Interrupt implements Runnable{
@Override
public void run() {
try {
Thread.sleep(8);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i=1;i<=100;i++){
if (Thread.interrupted()){
System.out.println("--------->"+Thread.currentThread().getName());
System.out.println("结束");
break;
}
System.out.println(i);
}
}
public static void main(String[] args) {
Thread th = new Thread(new Class04_Interrupt());
//就绪
th.start();
System.out.println(th.isInterrupted());
try {
Thread.sleep(9);
} catch (InterruptedException e) {
e.printStackTrace();
}
//为th线程添加中断标识
th.interrupt();
System.out.println(th.isInterrupted());
}
}
4)获取当前线程状态
/*
getState() 获取当前线程的状态
Thread.State 线程状态。 线程可以处于以下状态之一:
NEW
尚未启动的线程处于此状态。
RUNNABLE
在Java虚拟机中执行的线程处于此状态。
BLOCKED
被阻塞等待监视器锁定的线程处于此状态。多线程操作下,处于等待对象锁的线程处于这种状态
WAITING
无限期等待另一个线程执行特定操作的线程处于此状态。 wait(),join()
TIMED_WAITING
正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。阻塞与时间相关的线程处于这种状态 sleep(ms),join(ms),wait(ms)
TERMINATED
已退出的线程处于此状态。
*/
public class Class05_getStat implements Runnable{
public static void main(String[] args) {
Thread th = new Thread(new Class05_getStat());
System.out.println(th.getState()); //NEW
th.start();
System.out.println(th.getState()); //RUNNABLE
while (true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--->");
}
}
@Override
public void run() {
for(int i=1;i<=10;i++){
if (i==5){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
}
5)线程的优先级
/*
Priority 线程的优先级
线程的优先级越高,有限执行的可能性越大
1~10 线程优先级的数值范围
默认5 NORM_PRIORITY
最小1 MIN_PRIORITY
最大10 MAX_PRIORITY
setPriority(int) 设置一个线程的优先级
getPriority() 获取一个线程的优先级
*/
public class Class06_Priority implements Runnable{
public static void main(String[] args) {
Class06_Priority pri = new Class06_Priority();
Thread th = new Thread(pri,"A");
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}