多线程详解---(多案例实战)
Posted 乘凉者 栽树人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程详解---(多案例实战)相关的知识,希望对你有一定的参考价值。
多线程
1、区分单线程和多线程
- 单线程:就像是做饭,洗衣服,煮水,一个一个进行
- 多线程:在单线程的基础上,可以考虑煮水的时候,洗衣服节约时间
package com.kong.thread;
//创建线程,重写run方法,start方法开启线程
public class thread1 extends Thread
@Override
public void run()
//run方法线程体
for (int i = 0; i <1000 ; i++)
System.out.println("你好");
public static void main(String[] args)
thread1 thread1=new thread1();//创建线程
thread1.start();//start开启多线程
// thread1.run();//如果是run方法,只是将run方法运行,并不是开启多线程
for (int i = 0; i <1000 ; i++)
System.out.println(i);
测试结果:如果是run方法,就是按照你好输出完毕再输出i,如果是start(多线程)方法,则run方法跟i交替输出
2、网图下载
- 首先我们要知道的是多线程的调度,是CPU在操作的,而代码执行过程中,下载的网图是先后顺序的,但是如果跟第一点写的煮水洗衣服,是不是煮水会先好,多线程也是如此,就是一个争取CPU调度的过程
- 我们编写一段代码来试着探讨一下吧
package com.kong.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//1.下载图片,需要一个下载的方法
//2.编写构造器
//3.new一个下载方法
//4.编写main方法下载图片
public class thread2 extends Thread
private String url;
private String name;
public thread2(String url, String name)
this.url = url;
this.name = name;
@Override
public void run()
DownPicture downPicture=new DownPicture();
downPicture.down(url,name);
System.out.println(name+"下载完毕");
public static void main(String[] args)
thread2 t1=new thread2("http://kr.shanghai-jiuxin.com/file/2021/0609/1af55d6d59a1624ff57f5f30e19eaa4d.jpg","逢考必过1");
thread2 t2=new thread2("http://kr.shanghai-jiuxin.com/file/2021/0609/1af55d6d59a1624ff57f5f30e19eaa4d.jpg","逢考必过2");
thread2 t3=new thread2("http://kr.shanghai-jiuxin.com/file/2021/0609/1af55d6d59a1624ff57f5f30e19eaa4d.jpg","逢考必过3");
//开启多线程
t1.start();
t2.start();
t3.start();
//图片下载方法
class DownPicture
public void down(String url,String name)
try
FileUtils.copyURLToFile(new URL(url),new File(name));
catch (IOException e)
e.printStackTrace();
- 运行结果不难发现,三张相同的图片运行的顺序不一样,这是因为多线程的CPU调度,每个线程都在争取运行,导致相差不多的运行时间可以变化输出
3、Runable接口
启动线程方式:传入目标对象+Thread对象.start
package com.kong.thread;
public class runable implements Runnable
public void run()
for (int i = 0; i < 1000; i++)
System.out.println(i);
public static void main(String[] args)
runable runable=new runable();//创建线程
new Thread(runable).start();//开启线程
for (int i = 0; i < 1000; i++)
System.out.println("ni");
在Thread类里面,继承了runable接口
4、并发问题
package com.kong.thread;
//模拟购票
public class runable2 implements Runnable
//定义一些票数
private int tickNum=10;
public void run()
while(true)
if(tickNum<=1)
break;
//模拟购票操作所需时间
try
Thread.sleep(200);
catch (InterruptedException e)
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+"拿到第"+tickNum--+"票");
public static void main(String[] args)
runable2 runable2=new runable2();
new Thread(runable2,"小红").start();
new Thread(runable2,"小明").start();
new Thread(runable2,"小花").start();
注意:在模拟购票所需时间之后会出现一种一起同时购买同一张票的情况(主要原因是你还在买票时间,有人也在买这张票)
5、龟兔赛跑问题
package com.kong.thread;
public class race implements Runnable
private String winner=null;
public void run()
for (int i = 0; i <=100; i++)
//模拟兔子睡觉
if(Thread.currentThread().getName()=="兔子"&&i%10==0)
try
Thread.sleep(10);
catch (InterruptedException e)
e.printStackTrace();
boolean b = gameOver(i);
if(b)
break;
System.out.println(Thread.currentThread().getName()+"跑了"+i+"米");
private boolean gameOver(int foot)
if (winner!=null)
return true;
else if(foot>=100)
winner=Thread.currentThread().getName();
System.out.println(winner+"获得胜利");
return true;
return false;
public static void main(String[] args)
race race=new race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
6、静态代理模式
package com.kong.thread;
public class staticProxy
public static void main(String[] args)
weddingCompany wedding=new weddingCompany(new you());
wedding.HappyMarry();
interface Marry
void HappyMarry();
//你去实现一个结婚的方法,此处的你为真实角色
class you implements Marry
public void HappyMarry()
System.out.println("你要结婚了");
//结婚公司是作为代理角色
class weddingCompany implements Marry
private Marry target;
public weddingCompany(Marry target)
this.target=target;
public void HappyMarry()
before();
this.target.HappyMarry();
after();
private void before()
System.out.println("婚前准备");
private void after()
System.out.println("婚后送客");
7、Lambda表达式
函数式接口的定义:
- 任何接口,如果只包含一个抽象方法,就称为函数式接口
- 对于函数式接口,我们可以通过lambda表达式创建该接口对象
package com.kong.thread;
public class lambda
//静态内部类
// static class Like implements ILike
// public void lambda()
// System.out.println("你好啊");
//
//
public static void main(String[] args)
//局部内部类
// class Like implements ILike
// public void lambda()
// System.out.println("你好啊");
//
//
// ILike like=new Like();
// like.lambda();
//匿名内部类,只能借助父类或者接口
// ILike like = new ILike()
// public void lambda()
// System.out.println("你好啊");
//
// ;
// like.lambda();
//lambda简化
ILike like=()->
System.out.println("你好啊");
;
like.lambda();
//定义一个函数接口
interface ILike
void lambda();
//实现类
//class Like implements ILike
// public void lambda()
// System.out.println("你好啊");
//
//
总结
- 就是一个继承接口之后的简化
- 只适用于函数式接口
8、线程状态
- 创建状态:new一个对象,线程对象一旦创建就进入新生状态
- 就绪状态:当用start()方法式,线程立即进入就绪状态,但不一定马上调度
- 阻塞状态:调用sleep,wait或者同步锁定,线程就会进入阻塞章台,就是代码不往下执行,阻塞事件解除后,重新进入就绪状态,等待cpu的调度
- 执行状态:此处才是线程真正执行线程体的代码块
- 死亡状态:线程中断或者结束,都会让线程进入死亡状态,并且不可再重新启动
8.1、线程停止
- 建议线程正常停止—>利用次数,不建议死循环
- 建议使用标志位
- 不建议使用stop或者destroy
package com.kong.thread;
public class threadStop implements Runnable
//设置一个标识位
private boolean flag=true;
@Override
public void run()
int i=0;
while(flag)
System.out.println(i++);
public void stop()
this.flag=false;
public static void main(String[] args)
threadStop threadStop=new threadStop();
for (int i = 0; i < 100; i++)
System.out.println(i);
if(i==90)
threadStop.stop();
System.out.println("此线程停止");
8.2、线程休眠
- sleep(时间)指定当前线程阻塞的毫秒数
- sleep存在异常InterruptedException
- sleep时间到达后进程回进入就绪状态
- sleep可以模拟网络延时,倒计时等
- 每一个对象都有一个锁,sleep不会释放锁
package com.kong.thread;
import java.text.SimpleDateFormat;
import java.util.Date;
public class timeSleep
public static void main(String[] args)
tenDown();
public static void tenDown()
// //倒计时
// int num = 10;
// while (true)
// try
// Thread.sleep(1000);
// catch (InterruptedException e)
// e.printStackTrace();
//
// System.out.println(num--);
// if (num <= 0)
// break;
//
//
//
//打印系统当前的事件
Date date = new Date(System.currentTimeMillis());//获取当前系统时间
while(true)
try
Thread.sleep(1000);
catch (InterruptedException e)
e.printStackTrace();
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
date = new Date(System.currentTimeMillis());
作用:放大事件可能发生的概率
8.3、线程礼让
- 礼让线程,让当前正在执行的线程暂停,但是不阻塞
- 运行转为就绪
- cpu重新调度
package com.kong.thread;
public class threadYeid
public static void main(String[] args)
Myyied myyied = new Myyied();
new Thread(myyied,"a").start();
new Thread(myyied,"b").start();
class Myyied implements Runnable
@Override
public void run()
System.out.println(Thread.currentThread().getName()+"线程执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程停止");
结论:礼让不一定能成功
8.4、线程强制执行join(插队)
package com.kong.thread;
public class threadjoin implements Runnable
@Override
public void run()
for (int i = 0; i < 100; i++)
System.out.println(i);
public static void main(String[] args) throws InterruptedException
threadjoin threadjoin=new threadjoin();
Thread thread = new Thread(threadjoin);
thread.start();
for (int i = 0; i <50 ; i++)
if(i==20)
thread.join();
System.out.println("停止");
8.5、线程状态观察
package com.kong.thread;
public class state
public static void main(String[] args) throws InterruptedException
Thread thread=new Thread(()->
for (int i = 0; i < 10多线程详解---(多案例实战)