多线程
本章核心概念
线程就是独立的执行路径;
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
main()称之为主线程,为系统的入口,用于执行整个程序;
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预的。
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;线程会带来额外的开销,如cpu调度时间,并发控制开销。
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
线程创建
创建线程方式一:Extends Thread
继承Thread类,重写run()方法,调用start开启线程
线程开启不一定立即执行 由cpu调度
public class Thread13_2 extends Thread{
@Override
public void run() {
//run 方法线程体
for (int i = 0; i <200 ; i++) {
System.out.println("我在看代码"+i);
}
}
public static void main(String[] args) {
//创建线程对象
Thread13_2 thread13_2 = new Thread13_2();
//调用start()开启多线程
thread13_2.start();
for (int i = 0; i <2000 ; i++) {
System.out.println("我在学习多线程"+i);
}
}
}
多线程下载图片
package demo13;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
/**
* @ClassName CommonsIo13_3
* Description T0D0
* @Author WangYuanpeng
* Date 2021/4/1 16:39
* Version 1.0
**/
//实现多线程
public class CommonsIo13_3 extends Thread{
private String url;//网络地址
private String name;//文件名
public CommonsIo13_3(String url ,String name){
this.url = url;
this.name = name;
}
//下载图片线程执行体
@Override
public void run() {
Downloader downloader = new Downloader();
try {
downloader.downloader(url,name);
System.out.println("下载名"+name);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
CommonsIo13_3 t1 = new CommonsIo13_3("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=419416486,1672361391&fm=11&gp=0.jpg","1.jpg");
CommonsIo13_3 t2 = new CommonsIo13_3("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201205%2F03%2F01400598djmyeczcskh2yr.jpg&refer=http%3A%2F%2Fattach.bbs.miui.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619859396&t=a8261d33aff9a7b4f28540351692d71c","2.jpg");
CommonsIo13_3 t3 = new CommonsIo13_3("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201304%2F25%2F195133e7a1l7b4f5117y4y.jpg&refer=http%3A%2F%2Fattach.bbs.miui.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619859396&t=34e21c81c95e3621caa32627a1187317","3.jpg");
t1.start();
t2.start();
t3.start();
}
//下载器
class Downloader {
public void downloader(String url,String name) throws IOException {
try {
FileUtils.copyURLToFile(new URL(url) ,new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("io异常,downloader");
}
}
}
}
创建线程方式二 implements Runnable
实现Runnable
学习提示:查看JDK帮助文档
定义MyRunnable类实现Runnable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
package demo13;
/**
* @ClassName Runnable13_4
* Description T0D0
* @Author WangYuanpeng
* Date 2021/4/1 17:07
* Version 1.0
**/
public class Runnable13_4 implements Runnable {
@Override
public void run() {
//run 方法线程体
for (int i = 0; i <2000 ; i++) {
System.out.println("我在看代码"+i);
}
}
public static void main(String[] args) {
//创建线程对象
Runnable13_4 runnable13_4 = new Runnable13_4();
Thread thread = new Thread(runnable13_4);
thread.start();
//
for (int i = 0; i <2000 ; i++) {
System.out.println("我在学习多线程"+i);
}
}
}
Thread Runnable 小结
小结
◆继承Thread类
子类继承Thread类具备多线程能力
◆启动线程:子类对象.start()
不建议使用:避免OOP单继承局限性
◆实现Runnable接口
◆实现接口Runnable具有多线程能力
◆启动线程:传入目标对象+Thread对象.start()
◆推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
并发问题
多个线程操作同一个资源,线程不安全,数据紊乱
package demo13;
/**
* @ClassName Runnable13_6
* Description T0D0
* @Author WangYuanpeng
* Date 2021/4/2 15:59
* Version 1.0
**/
//多个线程操作同一个资源,线程不安全,数据紊乱
public class Runnable13_6 implements Runnable{
private int ticketNums = 10;
@Override
public void run() {
while (true){
if (ticketNums <= 0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums-- +"票");
}
}
public static void main(String[] args) {
Runnable13_6 runnable13_6 = new Runnable13_6();
new Thread(runnable13_6,"小明").start();
new Thread(runnable13_6,"小红").start();
new Thread(runnable13_6,"小雷").start();
}
}
Callable
静态代理模式
package demo13;
/**
* @ClassName Runnable13_7
* Description T0D0
* @Author WangYuanpeng
* Date 2021/4/2 16:13
* Version 1.0
**/
public class Runnable13_7 {
public static void main(String[] args) {
//代理对象 代理 真实对象
You you = new You();
new WeddingCompany(you).happyMarry();
}
}
//真实对象:你
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("我要结婚了,好hi呦");
}
}
//代理对象:婚庆公司
class WeddingCompany implements Marry{
//婚庆需要有你这个人 , 代理对象需要代理一个真实对象
private Marry you;
public WeddingCompany(Marry you){
this.you = you;
}
@Override
public void happyMarry() {
before();
this.you.happyMarry();//你要结婚
after();
}
private void before() {
System.out.println("结婚之前,布置洞房");
}
private void after() {
System.out.println("结婚之后,催你收钱");
}
}
//共同的接口:结婚
interface Marry{
void happyMarry();
}
//结婚之前,布置洞房
//我要结婚了,好hi呦
//结婚之后,催你收钱
lambda
love = (int a) -> {
System.out.println(“我喜欢lambda” + a);
package demo13;
/**
* @ClassName Lamda13_10
* Description T0D0
* @Author WangYuanpeng
* Date 2021/4/2 19:16
* Version 1.0
**/
public class Lambda13_10 {
//静态内部类
static class love1 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
public static void main(String[] args) {
//局部内部类
class love2 implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
Ilove love = new love(); //多态
love.lam(1);
love = new love1();
love.lam(2);
love = new love();
love.lam(3);
//匿名内部类
love = new Ilove() {
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
};
love.lam(4);
//lambda表达式
love = (int a) -> {
System.out.println("我喜欢lambda" + a);
};
love.lam(5);
}
}
//函数式接口
interface Ilove{
void lam(int a);
}
//外部类
class love implements Ilove{
@Override
public void lam(int a) {
System.out.println("我喜欢lambda" + a);
}
}
sleep 当地时间 和倒计时
package demo13;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;
/**
* @ClassName Sleep13_12
* Description T0D0
* @Author WangYuanpeng
* Date 2021/4/2 19:54
* Version 1.0
**/
public class Sleep13_12 {
public static void main(String[] args) {
// Sleep13_12 sleep13_12 = new Sleep13_12();
// sleep13_12.test();
//系统当前时间
Date startTime = new Date(System.currentTimeMillis());
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("yy:MM:dd:HH:mm:ss").format(startTime));
startTime = new Date(System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//倒计时
public void test(){
int i = 10;
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i--);
if (i<0){
break;
}
}
}
}
线程状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ePNY864R-1617800035530)(C:\Users\WangYuanpeng\AppData\Roaming\Typora\typora-user-images\image-20210402212621590.png)]
线程同步机制
形成条件:队列和锁[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p419YytI-1617800035532)(file:///C:\Users\WangYuanpeng\AppData\Local\Temp\SGPicFaceTpBq\11428\1EA0F7B8.png)]synchronized
会损失性能