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(); // 唤醒等待线程        }    }}

    优化效果

    • 数据保持一致。
    • 问题得到有效解决。
    • 性能得以优化。
    上一篇:在Window下安装kafka-manager
    下一篇:Object类

    发表评论

    最新留言

    关注你微信了!
    [***.104.42.241]2026年06月12日 03时18分59秒