Java多线程02:线程的同步和死锁+综合实战
数据不一致:可能出现重复生产或消费。 并发问题:生产一个,取一个,但可能出现重复操作。 优化后的
发布日期:2021-04-30 21:00:29
浏览次数:186
分类:精选文章
本文共 4467 字,大约阅读时间需要 14 分钟。
Java高级编程02: 线程同步与死锁
线程同步问题引出
在多线程环境下,多个线程可能会同时访问同一资源,若处理不当会导致数据错误。例如,三个线程同时出售5张票,可能会出现票数重复减少或超出范围的情况。
public class MyThread implements Runnable { private int ticket = 10; @Override public void run() { while (true) { if (this.ticket > 0) { System.out.println(Thread.currentThread().getName() + "卖票,ticket=" + this.ticket--); } else { System.out.println("***票已经卖光了***"); break; } } }}class ThreadDemo13 { public static void main(String[] args) { MyThread myThread = new MyThread(); new Thread(myThread, "票贩子A").start(); new Thread(myThread, "票贩子B").start(); new Thread(myThread, "票贩子C").start(); }} 为了验证问题,添加了延迟操作后,问题变得明显。三个票贩子可能会卖到负票数,说明没有有效的线程同步机制。
线程同步处理
线程同步的核心是锁机制。通过sync关键字定义同步代码块或同步方法,确保只允许一个线程执行特定操作。
1. 使用同步代码块
synchronized (this) { // 同步操作} 通常采用当前对象this进行同步。
2. 使用同步方法
public synchronized void sale() { // 同步操作} 在类库中,许多类使用同步方法进行处理。
线程死锁
死锁是多线程同步过程中可能出现的状态,多个线程互相等待对方释放资源。
例子
public class DeadLockTest { public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { @Override public void run() { try { System.out.println("线程1启动"); Thread.sleep(1000); System.out.println("线程1等待"); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { System.out.println("线程2启动"); Thread.sleep(1000); System.out.println("线程2等待"); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); }} 线程1和线程2可能会在对方的等待状态下,形成死锁。
生产者-消费者模型
生产者负责生产数据,消费者负责取用数据,需确保数据的一致性和正确性。
模型
生产者和消费者分别定义为线程类,共享数据对象。
例子
class Producer implements Runnable { private Message message; public Producer(Message message) { this.message = message; } @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } if (i % 2 == 0) { message.set("张三", "法外狂徒"); } else { message.set("李四", "合法公民"); } } }}class Consumer implements Runnable { private Message message; public Consumer(Message message) { this.message = message; } @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(message.get()); } }}class Message { private String name; private String content; public synchronized void set(String name, String content) { this.name = name; this.content = content; } public synchronized String get() { return this.name + "--" + this.content; }}public class MyThread { public static void main(String[] args) { Message message = new Message(); new Thread(new Producer(message)).start(); new Thread(new Consumer(message)).start(); }} 问题
解决方案
使用等待与唤醒机制
通过Object类的wait()和notify()方法,实现生产者-消费者的等待与唤醒。
优化后的Message类
class Message { private String name; private String content; private boolean allowProduction = true; // 允许生产 public synchronized void set(String name, String content) { if (!allowProduction) { try { super.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name; this.content = content; allowProduction = false; super.notify(); // 唤醒等待的线程 } public synchronized String get() { if (allowProduction) { try { super.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { return this.name + "--" + this.content; } finally { allowProduction = true; // 准备生产 super.notify(); // 唤醒等待线程 } }} 优化效果
- 数据保持一致。
- 问题得到有效解决。
- 性能得以优化。
发表评论
最新留言
关注你微信了!
[***.104.42.241]2026年06月12日 03时18分59秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
PHP获取IP的方法对比
2023-03-01
php获取json里面内容
2023-03-01
R2的版本由来
2023-03-01
PHP获取图片宽度高度、大小尺寸、图片类型、用于布局的img属性
2023-03-01
PHP获取当前文件的绝对路径
2023-03-01
PHP获取当前时间、时间戳的各种格式写法汇总
2023-03-01
PHP获取当前页面的完整URL
2023-03-01
php获取数据库中数据生成json,中文乱码问题的解决方案
2023-03-01
php获取文件夹中文件的两种方法
2023-03-01
PHP获取日期的一些方法总结
2023-03-01
R2学习记录
2023-03-01
PHP获取本周的每一天的时间
2023-03-01
php获取用户真实IP和防刷机制
2023-03-01
php获取网页内容的三种方法
2023-03-01
R-CNN算法优化策略
2023-03-01
PHP规范PSR0和PSR4的理解
2023-03-01
php解析ipa包,获取logo
2023-03-01
R&Rstudio安装各种包
2023-03-02
php设置cookie,在js中如何获取
2023-03-02
php设置socket超时时间
2023-03-02