Java多线程编程--(2)线程互斥与同步
线程互斥:多个线程操作同一个资源(即某个对象),为保证线程在对资源的状态(即对象的成员变量)进行一些非原子性操作后,状态仍然是正确的。最经典的就是火车售票。
package com.nemo.thread; public class TicketTest { static class Ticket{ int number = 100; public synchronized void sale(){//互斥 if(number<=0){ return; } System.out.println(Thread.currentThread().getName()+"sale"+(101-number)+"号票"); number--; } } public static void test(){ final Ticket ticket = new Ticket(); for(int i=1;i<=10;i++){ new Thread(new Runnable() { public void run() { while(ticket.number>0){ ticket.sale(); } } },String.valueOf(i)).start();; } } public static void main(String[] args) { test(); } }
结果:
1sale21号票
1sale22号票
1sale23号票
1sale24号票
5sale25号票
5sale26号票
5sale27号票
5sale28号票
5sale29号票
5sale30号票
5sale31号票
5sale32号票
线程同步:
同步的概念再于线程间通信,比较典型的例子就是“生产者-消费者问题”。多个生产者和多个消费者就是多条执行线程,他们共同操作一个数据结构中的数据,数据结 构中有时是没有数据的,这个时候消费者应该处于等待状态而不是不断的去访问这个数据结构。这里就涉及到线程间通信(当然此处还涉及到互斥,这里暂不考虑这 一点),消费者线程一次消费后发现数据结构空了,就应该处于等待状态,生产者生产数据后,就去唤醒消费者线程开始消费。生产者线程某次生产后发现数据结构 已经满了,也应该处于等待状态,消费者消费一条数据后,就去唤醒生产者继续生产。实现这种线程间同步,可以通过Object类提供的wait,notify, notifyAll 3个方法去进行即可
package com.nemo.thread; public class ProducerAConsumer { public static void main(String[] args) { final MessageQueue mq = new MessageQueue(10); // 创建3个生产者 for(int p=0;p<3;p++){ new Thread(new Runnable(){ @Override public void run() { while(true){ mq.put("消息来了!"); // 生产消息后,休息100毫秒 try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "Producer" + p).start(); } // 创建3个消费者 for(int s=0;s<3;s++){ new Thread(new Runnable(){ @Override public void run() { while(true){ mq.get(); // 消费消息后,休息100毫秒 try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "Consumer" + s).start(); } } /** * 内部类模拟一个消息队列,生产者和消费者就去操作这个消息队列 */ private static class MessageQueue{ private String[] messages;// 放置消息的数据结构 private int opIndex; // 将要操作的位置索引 public MessageQueue(int size) { if(size <= 0){ throw new IllegalArgumentException("消息队列的长度至少为1!"); } messages = new String[size]; opIndex = 0; } public synchronized void put(String message){ // Java中存在线程假醒的情况,此处用while而不是用if!可以参考Java规范! while(opIndex == messages.length){ // 消息队列已满,生产者需要等待 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } messages[opIndex] = message; opIndex++; System.out.println("生产者 " + Thread.currentThread().getName() + " 生产了一条消息: " + message); // 生产后,对消费者进行唤醒 notifyAll(); } public synchronized String get(){ // Java中存在线程假醒的情况,此处用while而不是用if!可以参考Java规范! while(opIndex == 0){ // 消息队列无消息,消费者需要等待 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } String message = messages[opIndex-1]; opIndex--; System.out.println("消费者 " + Thread.currentThread().getName() + " 消费了一条消息: " + message); // 消费后,对生产者进行唤醒 notifyAll(); return message; } } }
生产者 Producer0 生产了一条消息: 消息来了!
消费者 Consumer2 消费了一条消息: 消息来了!
生产者 Producer2 生产了一条消息: 消息来了!
消费者 Consumer0 消费了一条消息: 消息来了!
生产者 Producer1 生产了一条消息: 消息来了!
消费者 Consumer1 消费了一条消息: 消息来了!
浙公网安备 33010602011771号