当前位置: 首页 > news >正文

Java--多线程(上)

一、线程入门

1.1 线程和进程

进程
  • 一个正在运行的应用程序

    • 安装到电脑中的程序,如果没有被运行不能称为进程
  • 一个进程能同时执行多个任务

  • 每一个任务可以看做一个线程

线程
  • 进程的组成部分,称为轻量级进程
  • 线程是进程中具体执行任务的部分

1.2 线程的组成

CPU时间片
  • 指定时间内分配给线程的CPU资源
数据
  • 程序处理的数据
堆数据
  • 整个程序中所有线程共享的数据
栈数据
  • 每个线程独有的数据
逻辑代码
  • 驱动程序运行的代码

二、创建线程

2.1 继承Thread

1、创建类继承Thread

2、重写run方法

3、创建Thread子类对象

4、调用start方法启动线程

  • Thread子类
​
/***  Thread及其子类对象在Java中被称为线程对象*  */
public class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}
  • 创建线程并启动
​
public class Demo01 {public static void main(String[] args) {/***  1、创建类继承Thread*  2、重写run方法*  3、创建线程对象*  4、启动线程*/MyThread t01 = new MyThread();MyThread t02 = new MyThread();MyThread t03 = new MyThread();MyThread t04 = new MyThread();t01.start();t02.start();t03.start();t04.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}

2.2 实现Runnable

1、创建类实现Runnable接口

2、重写run方法

3、创建Runnable实现类对象

4、创建Thread对象

5、启动线程

​
public class Demo01 {public static void main(String[] args) {/***  1、创建类实现Runnable*  2、重写run方法*  3、创建Runnable实现类对象【任务】*  4、创建线程对象,加入任务*  5、调用start方法启动线程*/MyRunnable r = new MyRunnable();Thread t = new Thread(r);t.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}
​
/*** Runnable实现类*  具体的线程任务*/
class MyRunnable implements Runnable {
​@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}

三、常用方法

3.1 name和id

​
public class Demo01 {public static void main(String[] args) {/**long getId() 返回该线程的标识符。 String getName() 返回该线程的名称。 void setName(String name) 改变线程名称,使之与参数 name 相同。 static Thread currentThread() 返回对当前正在执行的线程对象的引用。 static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 */MyThread01 t = new MyThread01("一号线程");// 设置线程名称t.setName("壹号线程");t.start();}
}
​
class MyThread01 extends Thread{public MyThread01() {super();}
​public MyThread01(String name) {super(name);}
​@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===" + Thread.currentThread().getId() + "===>" + i);}}
}
​

3.2 休眠

​
public class Demo02 {public static void main(String[] args) throws InterruptedException {for (int i = 10; i > 0; i--) {System.out.println("发射倒计时:" + i);// 休眠指定毫秒值的时间Thread.sleep(1000);}System.out.println("发射");}}

3.3 优先级

​
public class Demo03 {public static void main(String[] args) {/**void setPriority(int newPriority) 更改线程的优先级。 */// 创建线程对象MyThread02 t01 = new MyThread02();MyThread02 t02 = new MyThread02();// 设置线程名字t01.setName("一号线程");t02.setName("222号线程");// 设置线程优先级t01.setPriority(1);t02.setPriority(10);// 启动线程t01.start();t02.start();}
}
​
class MyThread02 extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}

3.4 插队

​
public class Demo04 {public static void main(String[] args) throws InterruptedException {/**void join() 等待该线程终止。 */MyThread03 t = new MyThread03();t.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);if (i == 10) {// 子线程t插队t.join();}}}
}
​
class MyThread03 extends Thread {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}

3.5 守护线程

​
public class Demo05 {public static void main(String[] args) {/**void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 */// 创建线程MyThread04 t = new MyThread04();// 设置线程名字t.setName("后台线程");// 把设置为守护线程t.setDaemon(true);// 启动线程t.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}
class MyThread04 extends Thread {@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}

3.6 礼让线程

​
public class Demo06 {public static void main(String[] args) {/**static void yield() 暂停当前正在执行的线程对象,并执行其他线程。 */MyThread05 t = new MyThread05();t.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);if (i%10 == 0) {// 每逢10礼让一次Thread.yield();}}}
}
​
class MyThread05 extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "===>" + i);}}
}

四、多线程卖票【掌握】

4.1 继承Thread

​
public class Demo01 {public static void main(String[] args) {/***  火车站四个窗口,共同卖出100张车票,用多线程实现。*/// 创建线程TicketThread t01 = new TicketThread();TicketThread t02 = new TicketThread();TicketThread t03 = new TicketThread();TicketThread t04 = new TicketThread();// 设置名字t01.setName("一号窗口");t02.setName("22号窗口");t03.setName("叁号窗口");t04.setName("④号窗口");// 启动线程t01.start();t02.start();t03.start();t04.start();}
}
​
class TicketThread extends Thread {private static int ticket = 100;@Overridepublic void run() {while (true) {if (ticket <= 0) {break;}// 一号==100,二号==100,三号==100,四号==100ticket--;// 一号==99,二号==98,三号==97,四号==96System.out.println(Thread.currentThread().getName() + "卖出了第" + (100-ticket) + "张票,还剩下" + ticket);}}
}

4.2 实现Runnable

​
public class Demo02 {public static void main(String[] args) {// 创建卖票的任务,只需要创建一次TicketRunnable r = new TicketRunnable();// 创建4个线程Thread t01 = new Thread(r, "111号窗口");Thread t02 = new Thread(r, "222号窗口");Thread t03 = new Thread(r, "333号窗口");Thread t04 = new Thread(r, "444号窗口");// 启动线程t01.start();t02.start();t03.start();t04.start();}
}
​
class TicketRunnable implements Runnable {int ticket = 100;@Overridepublic void run() {while (true) {if (ticket <= 0) {break;}ticket--;System.out.println(Thread.currentThread().getName() + "卖出了第" + (100-ticket) + "张票,还剩下" + ticket);}}
}

五、多线程修改数组【掌握】

5.1 数组资源

​
import java.util.Arrays;
​
/***  数组资源*/
public class ArrSrc {String[] arr = new String[5];int index = 0;
​@Overridepublic String toString() {return "ArrSrc [arr=" + Arrays.toString(arr) + ", index=" + index + "]";}
​
}

5.2 线程A和B

  • ThreadA
​
public class ThreadA extends Thread {private ArrSrc arrSrc;public ThreadA(ArrSrc arrSrc) {super();this.arrSrc = arrSrc;}
​@Overridepublic void run() {// 存入数据arrSrc.arr[arrSrc.index] = "Hello";// 索引递增arrSrc.index++;}
}
  • ThreadB
​
public class ThreadB extends Thread {private ArrSrc arrSrc;public ThreadB(ArrSrc arrSrc) {super();this.arrSrc = arrSrc;}
​@Overridepublic void run() {// 存入数据arrSrc.arr[arrSrc.index] = "World";// 索引递增arrSrc.index++;}
}

5.3 测试

​
public class Demo01 {public static void main(String[] args) throws InterruptedException {/***  创建类*      测试类*      数组资源类*          数组*          索引*      线程A *          存入Hello*      线程B*          存入World*/// 创建数组和索引ArrSrc arrSrc = new ArrSrc();// 创建线程A和BThreadA a = new ThreadA(arrSrc);ThreadB b = new ThreadB(arrSrc);// 启动线程修改数组a.start();b.start();Thread.sleep(10);// 输出修改之后的数组System.out.println(arrSrc);}
}

六、线程安全【掌握】

6.1 问题

  • 当多个线程操作同一个共享资源的时候,如果操作分为多行代码执行
  • 在a线程执行期间时间片到期,b线程继续执行,如果往复执行可能出现线程安全问题

6.2 同步代码块

  • synchronized修饰的代码块称为同步代码块

  • 能确保原子操作不被破坏

    • a线程执行同步代码块期间,其他线程不能争夺时间片
    • a线程同步代码块执行结束之后,多条线程再同时争夺时间片
  • 同步锁

    • 多个线程共享的一个对象,线程把这个对象当做一个标记
    • 任何一条线程执行到同步代码块的时候获取这个锁对象,其他线程进入阻塞状态
    • 锁对象必须是对于多条线程惟一的对象
class TicketThread extends Thread {private static int ticket = 100;// 全局唯一的对象private static final Object LOCK = new Object();@Overridepublic void run() {while (true) {synchronized (LOCK) {if (ticket <= 0) {break;}// 一号==100ticket--;// 一号==99System.out.println(Thread.currentThread().getName() + "卖出了第" + (100-ticket) + "张票,还剩下" + ticket);}}}
}

6.3 同步方法

  • 使用synchronized修饰方法
  • 方法变成同步方法,只有被CPU分配了时间片的线程才能执行这个方法,执行期间不会切换其他线程
  • 需要线程执行结束这个方法才会释放锁对象,进入就绪状态,再次等待分配时间片
​
import java.util.Arrays;
​
/***  数组资源*/
public class ArrSrc {String[] arr = new String[5];int index = 0;/*** 修改数组的方法*  修改数组数据*  索引自增* @param str*/public synchronized void modifyArr(String str) {arr[index] = str;index++;}
​@Overridepublic String toString() {return "ArrSrc [arr=" + Arrays.toString(arr) + ", index=" + index + "]";}
​
}

七、线程状态

7.1 线程状态

  • 线程状态。线程可以处于下列状态之一:

    • NEW 至今尚未启动的线程处于这种状态。
    • RUNNABLE 正在 Java 虚拟机中执行的线程处于这种状态。
    • BLOCKED 受阻塞并等待某个监视器锁的线程处于这种状态。
    • WAITING 无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。
    • TIMED_WAITING 等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。
    • TERMINATED 已退出的线程处于这种状态。
  • 在给定时间点上,一个线程只能处于一种状态。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【OCPP】ocpp1.6协议第5.12章节Remote Stop Transaction的介绍及翻译
  • 这9个VXLAN术语还不精通?别干网工了
  • Ciallo~(∠・ω・ )⌒☆第二十一篇 入门re 正则表达式
  • 【设计模式】漫谈设计模式
  • 端点安全新纪元:EDR与XDR技术的融合应用
  • 洛谷 P6280 [USACO20OPEN] Exercise G
  • 【vue讲解:ref属性、动态组件、插槽、vue-cli创建项目、vue项目目录介绍、vue项目开发规范、es6导入导出语法】
  • Docker最佳实践进阶(二):Docker Compose容器编排
  • conda 常见使用命令详解
  • 单例模式下的自动内存释放和模板
  • 【C++初阶】:C++入门篇(一)
  • 计算机网络 —— 物理层
  • 了解Android
  • WPF 中,ControlTemplate 和 DataTemplate 是两种不同类型的模板和区别
  • 网络工程师学习笔记(一)
  • 08.Android之View事件问题
  • Angular 2 DI - IoC DI - 1
  • Docker 笔记(2):Dockerfile
  • Git学习与使用心得(1)—— 初始化
  • GraphQL学习过程应该是这样的
  • KMP算法及优化
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • PHP那些事儿
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • Python学习笔记 字符串拼接
  • Tornado学习笔记(1)
  • TypeScript实现数据结构(一)栈,队列,链表
  • vue 个人积累(使用工具,组件)
  • vue脚手架vue-cli
  • Webpack 4x 之路 ( 四 )
  • 阿里云购买磁盘后挂载
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 看域名解析域名安全对SEO的影响
  • 使用API自动生成工具优化前端工作流
  • 使用Gradle第一次构建Java程序
  • - 转 Ext2.0 form使用实例
  • 移动端高清、多屏适配方案
  • #define用法
  • #if和#ifdef区别
  • #Z0458. 树的中心2
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • (1)Jupyter Notebook 下载及安装
  • (2.2w字)前端单元测试之Jest详解篇
  • (21)起落架/可伸缩相机支架
  • (C语言)二分查找 超详细
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (zhuan) 一些RL的文献(及笔记)
  • (附源码)c#+winform实现远程开机(广域网可用)
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (六) ES6 新特性 —— 迭代器(iterator)
  • .Net Core 中间件验签
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .net 后台导出excel ,word