JAVA线程的同步与互斥

原创 2015年11月23日 22:25:49

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中的运行结果
这里写图片描述

相关文章推荐

java线程的同步互斥和通讯

一、同步和锁定 1、锁的原理 Java中每个对象都有一个内置锁。 当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例...

Java并发原语——线程、互斥与同步

本文首先介绍了Java的线程基本操作(创建、等待等),线程的互斥、同步操作;然后解释了为什么需要互斥、同步,什么是信号(通知)丢失,什么是虚假唤醒;并实验展示了原子性(Atomic)问题、通知丢失(n...

Java线程学习笔记(三)---线程同步互斥

该例子运用前面 Java线程学习笔记(二)---多线程同步方法 中提到的同步关键字synchronized来进行线程的同步互斥。synchronized在类的方法声明中使用,可以保证在同一时刻只有一个...

Java线程(四):JUC包线程互斥与同步以及读写锁

前言: 1、Java线程(一):传统线程的实现、互斥与通信 一、线程的互斥 (一)传统互斥:synchronized 关键字  1、synchronized(对象) 代码块需要锁定同一...

java的线程问题同步与互斥

1.java实现线程的方法;    1.实现Runnable接口,重写run方法,通过Thread的start方法启动线程。这种方法可以实现资源的共享    2.继承Thread类,重写run方法  ...

java基础——多线程(线程的同步互斥与通信)

一、线程的同步互斥的图文解说 二、多个线程访问共享对象和数据的方式 1、如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统...
  • bao9107
  • bao9107
  • 2013年10月14日 23:03
  • 638

Java多线程技术篇--线程的互斥与同步通信

一、使用银行转账来解释线程安全问题 同一个银行账户,在同一时间发生了转账汇款(解释:你刷卡消费了1000元的同时,你朋友给你转账了2000元)。这个时候是两个线程操作同一个数据,但是线程执行是随机的...

记JAVA的二三事(4)——线程的同步和互斥

概念 线程互斥的概念:当有多个线程(窗口)要访问同一个资源时(火车票),如果多个线程同时对该资源进行读和写操作,A窗口读取到剩余100张火车票,卖出一张,剩下99张,将剩余票数写入数据库。因为...

Java线程的同步与死锁

  • 2014年09月14日 14:56
  • 168KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JAVA线程的同步与互斥
举报原因:
原因补充:

(最多只允许输入30个字)