多线程的相关概念
多线程的相关概念
1.线程的两种实现方式
继承Thread类,实现Runnable接口
package com.lili.thread;
import sun.awt.windows.ThemeReader;
/**
* 线程的休眠
* 在当前线程的执行中,暂停指定的毫秒数 释放cpu的时间片
*
* @author: QiJingJing
* @create: 2021/7/14
*/
public class Test1 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
// 推荐
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
// 启动线程
myThread.start();
thread.start();
}
}
/**
* 实现线程的第一种方式:继承Thread类
*/
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 实现线程的第二种方式:实现Runnable接口
*/
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.Join与中断线程
加入线程,让调用线程先执行完毕,
package com.lili.thread;
/**
* join方法
* 加入线程,让调用线程先执行完毕
*
* @author: QiJingJing
* @create: 2021/7/14
*/
public class Test2 {
public static void main(String[] args) {
MyRunnable2 myRunnable2 = new MyRunnable2();
Thread thread2 = new Thread(myRunnable2);
thread2.start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 20) {
try {
// 让thread2线程执行完毕
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.interrupt();
}
}
}
}
class MyRunnable2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
中断线程适合自定义标记中断线程:
package com.lili.thread;
/**
* @author: QiJingJing
* @create: 2021/7/14
*/
public class Test2 {
public static void main(String[] args) {
MyRunnable2 myRunnable2 = new MyRunnable2();
Thread thread2 = new Thread(myRunnable2);
thread2.start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 20) {
myRunnable2.flag = false;
}
}
}
}
class MyRunnable2 implements Runnable {
public boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println(Thread.currentThread().getName() + "--" + i++);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.守护线程与yield
public final void setDaemon(boolean on):将此线程标记为daemon线程或用户线程,当运行的唯一线程是守护线程时,java虚拟机将退出
yield():让出本次cpu执行权,但不一定礼让成功
package com.lili.thread;
/**
* 守护线程和yield
*
* @author: QiJingJing
* @create: 2021/7/14
*/
public class Test3 {
public static void main(String[] args) {
Runnable3 runnable3 = new Runnable3();
Thread thread = new Thread(runnable3);
// 线程可以分为守护线程和用户线程,当进程中没有用户线程时,JVM会退出
// 设置为守护线程
thread.setDaemon(true);
//设置优先级可以提高该线程抢得cpu的概率
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
for (int i = 0; i < 50; i++) {
System.out.println("main--" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 5) {
Thread.yield();//让出本次cpu的执行权
}
}
}
}
class Runnable3 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("--" + i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4.线程同步
(1)同步代码块 (2)使用同步方法 (3)使用Lock锁(更灵活的代码控制)
package com.lili.thread;
import java.util.concurrent.locks.ReentrantLock;
/**
* 1.多线程共享数据时,会发生线程不安全的情况
* 2、多线程共享数据必须实现同步,
* 3.实现同步的三种方法:
* (1 同步代码块
* (2 使用同步方法
* (3 使用lock(更灵活的代码控制)
* 多线程共享数据,会有安全问题,使用同步可以解决安全问题,但同时会牺牲性能,所以同步的代码块尽量保持简短,把不随线程变化的代码移除同步,不要阻塞
*
* @author: QiJingJing
* @create: 2021/7/15
*/
public class Test4 {
public static void main(String[] args) {
MyRunnable5 myRunnable5 = new MyRunnable5();
Thread t1 = new Thread(myRunnable5);
Thread t2 = new Thread(myRunnable5);
t1.start();
t2.start();
}
}
class MyRunnable5 implements Runnable {
private int ticket = 10;// 售票
// @Override
// // 可以写方法中,表示为同步方法
// public /*synchronized*/ void run() {
// for (int i = 0; i < 300; i++) {
// synchronized (this) {
// if(ticket>0){
// ticket--;
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("你购买的票剩余"+ticket+"张");
// }
// }
// }
// }
ReentrantLock lock = new ReentrantLock();
//lock实现同步
@Override
// 可以写方法中,表示为同步方法
public void run() {
for (int i = 0; i < 300; i++) {
lock.lock();//上锁
try {
if (ticket > 0) {
ticket--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("你购买的票剩余" + ticket + "张");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//解锁
}
}
}
}
5.死锁
过多的同步有可能出现死锁,死锁的操作一般是在程序运行的时候才可能出现,多线程中要进行资源的共享,就需要同步,但同步过多,就可能造成死锁:
package com.lili.thread;
/**
* 死锁例子
*
* @author: QiJingJing
* @create: 2021/7/15
*/
public class Test5 {
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj1) {
System.out.println("obj1");
synchronized (obj2) {
System.out.println("obj2");
}
}
}).start();
new Thread(() -> {
synchronized (obj2) {
System.out.println("obj2");
synchronized (obj1) {
System.out.println("obj1");
}
}
}).start();
}
}
6,生产者与消费者
(1)管程法
package com.lili.thread;
/**
* 测试生产者消费者模型(管程法)
*
* @author: QiJingJing
* @create: 2021/7/15
*/
public class Test6 {
public static void main(String[] args) {
Buffer buf = new Buffer();
new Thread(new Productor(buf)).start();
new Thread(new Consumer(buf)).start();
}
}
// 生产者
class Productor implements Runnable {
private Buffer buffer;
public Productor(Buffer buffer) {
this.buffer = buffer;
}
// 生产
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
buffer.push(new Chicken(i));
System.out.println("成产了" + i + "只鸡");
}
}
}
// 消费者
class Consumer implements Runnable {
private Buffer buffer;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
// 生产
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println("消费了第" + buffer.pop().getId() + "只鸡");
}
}
}
// 产品
class Chicken {
private int id;
public Chicken(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
// 缓冲区
class Buffer {
// 需要一个容器大小
private Chicken[] chickens = new Chicken[10];
// 容器计数器
private int count = 0;
// 生产者放入产品
public synchronized void push(Chicken chicken) {
//如果容器满了,需要等待消费者消费
if (count == chickens.length) {
//通知消费者消费,生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果没满,我们要丢入产品
chickens[count] = chicken;
count++;
// 可以通知消费者消费了
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken pop() {
// 判断能否消费
if (count == 0) {
//等待生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果可以消费
count--;
Chicken chicken = chickens[count];
// 通知生产者生产
this.notifyAll();
return chicken;
}
}
(2)信号灯法
package com.lili.thread;
/**
* 生产者与消费者(信号灯法)
*
* @author: QiJingJing
* @create: 2021/7/15
*/
public class Test7 {
public static void main(String[] args) {
TV tv = new TV();
new Thread(new Player(tv)).start();
new Thread(new Watcher(tv)).start();
}
}
// 生产者->演员
class Player implements Runnable {
private TV tv;
public Player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
this.tv.play("快乐大本营播放中");
} else {
this.tv.play("抖音:记录美好生活");
}
}
}
}
// 消费者->观众
class Watcher implements Runnable {
private TV tv;
public Watcher(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
this.tv.watch();
}
}
}
// 产品-节目
class TV {
private String voice;// 表演的节目
private boolean flag = true;
// 表演
public synchronized void play(String voice) {
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了" + voice);
// 通知群众观看
this.notifyAll();
this.voice = voice;
this.flag = !this.flag;
}
// 观看
public synchronized void watch() {
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观众观看了" + voice);
// 通知演员表演
this.notifyAll();
this.flag = !this.flag;
}
}
7.线程池
背景:经常创建和销毁,使用量特别大的资源,比如并发下的线程,对性能影响很大
思路:提前创建好多个线程,放入线程池,使用时直接获取,使用完放回池中,可以避免频繁创建销毁,实现重复利用,类似生活中的交通工具
package com.lili.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author: QiJingJing
* @create: 2021/7/15
*/
public class Test8 {
public static void main(String[] args) {
// 1.创建服务,创建线程池
// 参数为线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new MyRunnable7());
service.execute(new MyRunnable7());
service.execute(new MyRunnable7());
service.execute(new MyRunnable7());
//2. 关闭链接
service.shutdown();
}
}
class MyRunnable7 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!