多线程学习笔记01线程、进程、多线程与线程创建

注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。

核心概念总结:

  • 线程就是独立的执行路径;
  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  • main()称之为主线程,为系统的入口,用于执行整个程序;
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的。
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  • 线程会带来额外的开销,如cpu调度时间,并发控制开销;
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

2线程创建

三种创建方式

在这里插入图片描述

Thread类
  • 自定义线程类继承Thread类

  • 重写run()方法,编写线程执行体

  • 创建线程对象,调用start()方法启动线程

继承Thread()类创建线程:

//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程

public class TestThread1 extends Thread{

@Override

public void run() {

//run方法线程体

for (int i = 0; i < 20; i++) {

System.out.println(“我在看代码—” + i);

}

}

public static void main(String[] args) {

//主线程

//创建一个线程对象 调用start方法开启线程

TestThread1 testThread1 = new TestThread1();

testThread1.start();

for (int i = 0; i < 20; i++) {

System.out.println(“我在学习多线程–” + i);

}

}

}

在这里插入图片描述

testThread1.start();改为testThread1.run();,注意观察执行顺序:

在这里插入图片描述

调用start()方法是同时执行的,而调用run()方法是先跑完run()方法,再跑下一个

注意:

  • 线程开启不一定立即执行,由CPU调度执行
网图下载

在这里插入图片描述

需要commons-io.jar包

将jar包复制到文件夹中,并右击“add as Library”

在这里插入图片描述

import org.apache.commons.io.FileUtils;

import java.io.File;

import java.io.IOException;

import java.net.URL;

//练习Thread实现一个多线程同步下载图片

public class TestThread2 extends Thread {

private String url;//网络图片地址

private String name;//保存的文件名

public TestThread2(String url, String name) {

this.url = url;

this.name = name;

}

//下载图片线程的执行体

@Override

public void run() {

WebDownLoader webDownLoader = new WebDownLoader();

webDownLoader.downLoader(url, name);

System.out.println(“下载了文件,名为:” + name);

}

public static void main(String[] args) {

TestThread2 t1 = new TestThread2(“https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2F2021%2Fedpic_source%2F1d%2F31%2F79%2F1d3179f050039cc45f9f62a105b12c3a_8.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646039329&t=700647f4c668754644f743467bda0e09”, “1.jpg”);

TestThread2 t2 = new TestThread2(“https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2F2021%2Fedpic_source%2F1d%2F31%2F79%2F1d3179f050039cc45f9f62a105b12c3a_8.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646039329&t=700647f4c668754644f743467bda0e09”, “2.jpg”);

TestThread2 t3 = new TestThread2(“https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2F2021%2Fedpic_source%2F1d%2F31%2F79%2F1d3179f050039cc45f9f62a105b12c3a_8.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646039329&t=700647f4c668754644f743467bda0e09”, “3.jpg”);

t1.start();

t2.start();

t3.start();

}

}

class WebDownLoader {

//下载方法

public void downLoader(String url, String name) {

try {

FileUtils.copyURLToFile(new URL(url), new File(name));

} catch (IOException e) {

e.printStackTrace();

System.out.println(“IO异常,downLoader方法出现问题”);//异常提醒

}

}

}

在这里插入图片描述

实现Runnable
  • 定义MyRunnable类实现Runnable接口

  • 实现run()方法,编写线程执行体

  • 创建线程对象,调用start()方法启动线程

//创建线程方式二:实现Runnable接口

public class TestThread3 implements Runnable{

@Override

public void run() {

//run方法线程体

for (int i = 0; i < 20; i++) {

System.out.println(“我在看代码—” + i);

}

}

public static void main(String[] args) {

//创建runnable接口的实现类对象

TestThread3 testThread3 = new TestThread3();

//创建线程对象,通过线程对象开启线程

// Thread thread = new Thread();

// thread.start();

new Thread(testThread3).start();

for (int i = 0; i < 20; i++) {

System.out.println(“我在学习多线程–” + i);

}

}

}

在这里插入图片描述

线程同时执行。

小结:

  • 继承Thread类:
子类继承Thread类具备多线程能力  
启动线程:子类对象.start()  
**不建议使用,,避免OOP单继承局限性**
  • 实现Runnable接口:
实现接口Runnable具有多线程能力  
启动线程:传入目标对象+Thread对象.start()  
**推荐使用,,避免单继承局限性,灵活方便,方便同一个对象被多个线程使用**
初识并发问题

典型案例:买火车票

//多个线程同时操作同一个对象

//买火车票

public class TestThread4 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) {

TestThread4 testThread4 = new TestThread4();

new Thread(testThread4, “小明”).start();

new Thread(testThread4, “小红”).start();

new Thread(testThread4, “黄牛”).start();

}

}

在这里插入图片描述

其中:

Thread.currentThread().getName():获得当前执行线程的名字

Thread.sleep(200);:模拟延时

但是通过观察运行情况,发现有不同人拿到同一张票的情况,即多个线程操作同一个资源,线程不安全。

案例:龟兔赛跑

//模拟龟兔赛跑

public class Race implements Runnable {

//胜利者

private static String winner;

@Override

public void run() {

for (int i = 0; i <= 100; i++) {

//模拟兔子睡觉

if (Thread.currentThread().getName().equals(“兔子”)&&i%10==0) {

try {

Thread.sleep(1);

计算机网络

  • HTTP 缓存

  • 你知道 302 状态码是什么嘛?你平时浏览网页的过程中遇到过哪些 302 的场景?

  • HTTP 常用的请求方式,区别和用途?

  • HTTPS 是什么?具体流程

  • 三次握手和四次挥手

  • 你对 TCP 滑动窗口有了解嘛?

  • WebSocket与Ajax的区别

  • 了解 WebSocket 嘛?

  • HTTP 如何实现长连接?在什么时候会超时?

  • TCP 如何保证有效传输及拥塞控制原理。

  • TCP 协议怎么保证可靠的,UDP 为什么不可靠?

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

算法

  • 链表

  • 字符串

  • 数组问题

  • 二叉树

  • 排序算法

  • 二分查找

  • 动态规划

  • BFS

  • DFS

  • 回溯算法

  • 29
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值