大块木

一步一脚印

JAVA线程的同步与互斥

1、什么是同步,互斥。
同步一般有互斥一起讨论。在多道程序设计的操作系统中,由于存在并发执行(多个进程抢占一处理机的使用权),所以各个进程间的存在资源共享和相互合作的问题。而同步就是进程间的直接制约问题互斥是申请临界资源进程间的间接制约问题


2、什么是线程。
由于进程是一个拥有资源的独立单位,在各个进程抢夺处理机的被调度的过程会,系统会付出较大的时间开销,所引入了纯程,将纯程作为调度和分配资源的基本单位,用户可以通过创建线程完成任务,以减少系统开销。打开任务管理器(Ctrl+Shift+Esc),进程选项卡里正在运行的就是当前所有进程。


3、生产商与消费者(同步)
多个生产商与多个消费者共用一个仓库,这个仓库就是临界资源,生产商会不断的生产商品,消费者同样也在不断的消费,但当仓库满仓时,生产商应该停止生产了(wait()),但消费者同时还在不断的消费,当仓库有空闲仓位时,生产商就应该被唤醒(notify()),继续生产。同样消费者也是,当仓库没有商品时,消费者也应该停止消费,等生产商生产出商品后,才继续消费。


class Store {
    // 仓位最多为20个
    private final int MAX = 20;
    private int num = 0;

    /**
     * 生产商生产的产品入库
     */
    public synchronized void produce(Producer producer) {
        while (num == MAX) {
            try {
                System.out.println("仓库已满 ,请等待空位");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        ++num;
        System.out.println(producer.name+" 生产了后,仓库现存 :" + num+"个产品");
        notify();//唤醒其它进程
    }

    /**
     * 消费者消费商品出库
     */
    public synchronized void consume(Comsumer consumer) {
        while (num == 0) {
            try {
                System.out.println("仓库空仓,请等待产品入库");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        --num;
        System.out.println(consumer.name+" 消费后,还剩 :" + num+"个产品");
        notify();//唤醒其它进程
    }
}

/**
 * 生产商类,不断地生产产品
 */
class Producer implements Runnable {
    String name;
    Store store;

    public Producer(String name,Store store) {
        this.name=name;
        this.store = store;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep((long) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            store.produce(this);
        }
    }

}

/**
 * 消费者类,不断地消费产品
 */
class Comsumer implements Runnable {
    String name;
    Store store;
    public Comsumer(String name,Store store) {
        this.name = name;
        this.store=store;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep((long) (Math.random() % 30 * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            store.consume(this);
        }
    }

}

public class Main {

    public static void main(String[] args) {
        Store store = new Store();
        new Thread(new Comsumer("张三",store)).start();
        new Thread(new Comsumer("李四",store)).start();
        new Thread(new Comsumer("王五",store)).start();
        new Thread(new Producer("第一工厂",store)).start();
        new Thread(new Producer("第二工厂",store)).start();
        new Thread(new Producer("第三工厂",store)).start();
    }
}

4、车票售卖(互斥)
一个车站有多个售票窗口,如果每个售票窗口就相当于一个线程,车票就是互斥线程争夺的临界资源。为了保障信息的完整性、安全性和封闭性。所以对于临界资源必须保护起来。在java语言中就是加synchronized关键字,告诉系统,这是一个临界资源,一个只能一个线程访问。如果不加synchronized关键字,就有可能出现数据丢失或读取脏数据的错误。就以下代码,如果sale()方法没有加synchronized关键字,num就可能输出-1,-2等错误的数据,但事实上,车票是没有负数的。


class Ticket {
    private int num = 10;

    /**
     * sale()方法代表销售车票,如果不加synchronized关键字,可能有负数输出
     */
    public synchronized void sale(Window window) {
        if (num > 0) {
            // 输出当前有多少张车票
            System.out.println(window.name + "售出票,还剩 :" + --num);
        } else {
            try {
                // 车票售完后,所有线程等待
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

/**
 * 窗口类
 */
class Window implements Runnable {
    String name;
    Ticket ticket;

    public Window(String name, Ticket ticket) {
        super();
        this.name = name;
        this.ticket = ticket;
    }

    @Override
    public void run() {
        while (true) {
            try {
                // 等待[0,3)秒
                long time = (long) (Math.random() * 3) * 1000;
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket.sale(this);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        // 三个售票窗口,相当三个互斥线程
        new Thread(new Window("窗口一", t)).start();
        new Thread(new Window("窗口二", t)).start();
        new Thread(new Window("窗口三", t)).start();
    }
}

在eclipse中的运行结果
这里写图片描述

阅读更多
文章标签: 同步 互斥
个人分类: JavaSE
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭