多线程

it2023-10-06  88

多线程

1.概念

1.1 进程

进程:进行(执行)中的应用程序,我们称之为进程。进程属于CPU分配资源的最小单位。

1.2 线程

线程:线程属于CPU执行调度的最小单位。

1.3 进程和线程的关系

1.线程包含在进程之中,一个进程至少包含一个线程。

举例:进程和线程就像车身和车轮,车轮不是越多越好(线程不是越多越好,要根据实际的硬件环境)

1.4 线程的执行

多个线程是由CPU根据每个线程分配的时间片来决定随机轮流执行的。每个线程最多占用20ms,过了这个时间将切换的其他的线程。

1.5 并发和并行

举例:比如你去饭店点了两盘菜,最后你将这两盘菜吃完了,从饭店老板的角度来看属于同时吃完的,但是严格意义上来说,属于轮流交替吃完的。这中属于并发。并行是指比如你和你的同桌两个人,一人点一盘菜,这样才属于并行。

并发:同时发生,轮流交替来执行

并行:真正意义上的同时执行

2.线程的创建

2.1 继承Thread类

1.继承Thread类,重写run()方法

2.适用于单继承,书写简单

package com.qfedu.test1; /** * 创建线程方式1: * 继承Thread类 重写run方法 创建线程对象 * @author WHD * */ public class Test2 extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "在 执行"); } public static void main(String[] args) { Test2 th1 = new Test2(); th1.start(); // th1.run(); Test2 th2 = new Test2(); th2.start(); } }
2.2 实现Runnable接口

实现Runnable接口,重写run()方法

1.避免了单继承的局限性

2.便于数据的共享

package com.qfedu.test1; /** * 创建线程方式2: * 实现Runnable接口 重写run方法 * * @author WHD * */ public class Test3 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "在执行"); } public static void main(String[] args) { Test3 t = new Test3(); Thread th1 = new Thread(t, "线程A"); th1.start(); // th1.run(); } }
2.3 调用start方法和调用run方法的区别(面试题)

调用start方法将会开启一个新的线程,但是调用run方法不会开启新的线程,只是使用main线程调用方法。

3.线程的状态(面试题)

1.创建 new Thread对象

2.就绪 start方法

3.运行 run方法

4.阻塞 sleep 、join方法

5.死亡 线程执行完毕

package com.qfedu.test2; /** * 线程的状态 * @author WHD * */ public class Test2 implements Runnable{ @Override public void run() { // 执行 try { // 阻塞 Thread.sleep(2000); // 休眠属于阻塞状态的表现之一 } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "线程" + i); } // 死亡 } public static void main(String[] args) { Test2 t1 = new Test2(); Thread th1 = new Thread(t1,"线程A"); // 创建 Thread th2 = new Thread(t1,"线程B"); th1.start(); // 就绪 th2.start(); } }

4.线程常用的方法

currentThread() 获取当前线程对象

getName() 获取线程名称

setName() 设置线程名称

getPriority() 获取线程优先级

stop() 停止当前线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dp5tmCjH-1603197207912)(.\img\线程方法1.png)]

package com.qfedu.test2; /** * 线程的优先级 * 默认为5 最大10 最小1 * MAX_PRIORITY 10 * MIN_PRIORITY 1 * NORM_PRIORITY 5 * setPriority()设置优先级 * getPriority()获取优先级 * @author WHD * */ public class Test3 extends Thread{ @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "线程执行" + i); } } public static void main(String[] args) { Test3 th1 = new Test3(); Test3 th2 = new Test3(); th1.setName("线程A"); th2.setName("线程B"); th1.setPriority(Thread.MAX_PRIORITY); th2.setPriority(Thread.MIN_PRIORITY); System.out.println(th1.getPriority()); System.out.println(th2.getPriority()); th1.start(); th2.start(); } } package com.qfedu.test2; /** * 线程的休眠 * sleep(long 毫秒) * sleep(long 毫秒,int 纳秒) * @author WHD * */ public class Test4 extends Thread{ @Override public void run() { // 检查异常 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } public static void main(String[] args) { Test4 th1 = new Test4(); th1.start(); } } package com.qfedu.test2; /** * 线程的插队 * join() 直到插队线程执行完毕 被插队线程再继续执行 * join(long 毫秒) 被插队线程等待指定的时间 时间过后继续轮流交替来执行 * join(long 毫秒,int 纳秒) 被插队线程等待指定的时间 时间过后继续轮流交替来执行 * @author WHD * */ public class Test5 extends Thread{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName() + "在执行" + i + "============================"); } } public static void main(String[] args) throws InterruptedException { Test5 th1 = new Test5(); th1.start(); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "主线程" + i); if(i == 10) { th1.join(); } } } } package com.qfedu.test2; /** * 线程的礼让 * 并不能保证一定会礼让其他线程 只是提供一种可能 用于缓解并发的问题 * yield() 礼让 * @author WHD * */ public class Test6 extends Thread{ @Override public void run() { for (int i = 0; i < 20; i++) { if(i == 3) { System.out.println("线程礼让"); Thread.yield(); // 当前线程会礼让 如果此时本来执行的是线程A 执行完礼让 有可能会执行线程B } System.out.println(Thread.currentThread().getName() + "在执行"); } } public static void main(String[] args) { Test6 th1 = new Test6(); Test6 th2 = new Test6(); th1.setName("线程A"); th2.setName("线程B"); th1.start(); th2.start(); } } package com.qfedu.test2; /** * 线程的中断(停止) * interrupt() 设置线程中断标识为true 标识 此线程可以被中断 * interrupted() 打印当前线程的是否可被中断 * stop() 停止线程 * @author WHD * */ public class Test7 extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { if(i == 5) { Thread.currentThread().interrupt(); Thread.currentThread().stop(); } System.out.println(Thread.currentThread().getName() + "再执行" + i + "是否可被中断状态" + Thread.interrupted()); } } public Test7(String name) { super(name); } public static void main(String[] args) { Test7 th1 = new Test7("线程A"); th1.start(); } } package com.qfedu.test2; /** * isAlive() 判断线程是否还存活 * @author WHD * */ public class Test8 extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行" + i); } } public static void main(String[] args) throws InterruptedException { Test8 th1 = new Test8(); th1.setName("线程A"); th1.start(); Thread.sleep(1000); System.out.println("是否还存活" + th1.isAlive()); Thread.sleep(5000); System.out.println("是否还存活" + th1.isAlive()); } }

5.线程安全synchronized关键字

在多线程访问同一个资源的情况,因为线程运行的特点:线程是随机轮流交替来执行的,所以多个线程访问同一个数据,会出现问题,我们可以使用同步关键字来解决

synchronized:

1.用于修饰代码块

​ a.同一时间只能有一个线程访问同步代码块中的内容

​ b.但是 其他线程可以访问没有被同步代码块包括的代码

​ c.其他的同步代码块 同样被锁定 (这些多个同步代码块所锁定的是同一个对象 比如 this)

2.用于修饰方法

​ 表示被同步关键字修饰的方法同一时间只能有一个线程访问

package com.qfedu.test4; /** * 假设有10张票 * 三个人抢票 * 票号是唯一的 总数不能超过10张 * 目前存在问题: * 数量不能保证10个 * 票号不能保证唯一 * synchronized 同步的意思 * 适用场景 * 1.同步代码块 * a.同一时间只能有一个线程访问同步代码块中的内容 * b.但是 其他线程可以访问没有被同步代码块包括的代码 * c.其他的同步代码块 同样被锁定 (这些多个同步代码块所锁定的是同一个对象 比如 this) * 2.同步方法 * a.表示当前方法同一时间只有一个线程可以访问 * @author WHD * */ public class BuyTicket2 implements Runnable{ private int ticketCount = 10; Object obj = new Object(); @Override public void run() { while(true) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // synchronized 同步 synchronized (obj) { if(ticketCount == 0) { break; } ticketCount --; System.out.println(Thread.currentThread().getName() + "抢到第"+(10 - ticketCount) +"张票,还剩余" + ticketCount); } // synchronized (this) { // System.out.println("hello word"); // } // 其他逻辑代码 } } public static void main(String[] args) { BuyTicket2 bt = new BuyTicket2(); Thread zhaosi = new Thread(bt, "赵四"); Thread guangkun = new Thread(bt, "广坤"); Thread dana = new Thread(bt, "大拿"); zhaosi.start(); guangkun.start(); dana.start(); } } package com.qfedu.test4; /** * 假设有10张票 * 三个人抢票 * 票号是唯一的 总数不能超过10张 * 目前存在问题: * 数量不能保证10个 * 票号不能保证唯一 * synchronized 同步的意思 * 适用场景 * 1.同步代码块 * a.同一时间只能有一个线程访问同步代码块中的内容 * b.但是 其他线程可以访问没有被同步代码块包括的代码 * c.其他的同步代码块 同样被锁定 (这些多个同步代码块所锁定的是同一个对象 比如 this) * 2.同步方法 * a.表示当前方法同一时间只有一个线程可以访问 * @author WHD * */ public class BuyTicket3 implements Runnable{ private int ticketCount = 10; Object obj = new Object(); @Override public synchronized void run() { while(ticketCount > 0) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } ticketCount --; System.out.println(Thread.currentThread().getName() + "抢到第"+(10 - ticketCount) +"张票,还剩余" + ticketCount); } } public static void main(String[] args) { BuyTicket3 bt = new BuyTicket3(); Thread zhaosi = new Thread(bt, "赵四"); Thread guangkun = new Thread(bt, "广坤"); Thread dana = new Thread(bt, "大拿"); zhaosi.start(); guangkun.start(); dana.start(); } }

6. 线程安全的类

线程安全:StringBuffer,Vector,Hashtable 以上这些类的方法都使用同步关键字修饰

线程不安全:StringBuilder,ArrayList,LinkedList,HashSet,HashMap,TreeSet…… 没有使用同步关键字修饰

() + “抢到第”+(10 - ticketCount) +“张票,还剩余” + ticketCount); } }

public static void main(String[] args) { BuyTicket3 bt = new BuyTicket3(); Thread zhaosi = new Thread(bt, "赵四"); Thread guangkun = new Thread(bt, "广坤"); Thread dana = new Thread(bt, "大拿"); zhaosi.start(); guangkun.start(); dana.start(); }

}

#### 6. 线程安全的类 > 线程安全:StringBuffer,Vector,Hashtable 以上这些类的方法都使用同步关键字修饰 > > 线程不安全:StringBuilder,ArrayList,LinkedList,HashSet,HashMap,TreeSet…… 没有使用同步关键字修饰
最新回复(0)