码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA 多线程开篇 -从按顺序打印ABC开始

时间:2015-09-03 23:08:02      阅读:544      评论:0      收藏:0      [点我收藏+]

标签:

序言

  很想把一个问题弄清楚,特别是以前一直模模糊糊的并发编程,今天在华为OJ上碰到一道题,“顺序打印ABC的两种方法开始写起”,就以这道题开篇,希望日后有时间把并发编程的基本问题弄清楚。

问题

  启动三个线程,一个线程打印A,一个打印B,一个打印C,按顺序打印ABC....。如输入3,输出就是“ABCABCABC”

程序

  线程的调度是由系统操作的,要想多个线程按照要求顺序打印,就必须做好线程间的同步。

 思路:四个线程循环打印,但是一个线程打印一个字母释放锁后无法确定获得锁的是哪一个线程,这就需要用一个标志判断是否轮到自己打印,是的话就打印,然后让下一个线程线程打印,否则等待。

 主要有两种方法:

  1、使用synchronized关键字,以及对象的wait、notify和notifyAll方法

  2、使用Lock和Condition

  这里先给出第二种的程序,打印ABCD。

  1 import java.util.Scanner;
  2 import java.util.concurrent.locks.Condition;
  3 import java.util.concurrent.locks.Lock;
  4 import java.util.concurrent.locks.ReentrantLock;
  5 
  6 public class Main {
  7     public static void main(String[] args) throws Exception  
  8     {
  9         Scanner scanner=new Scanner(System.in);
 10         int n=scanner.nextInt();
 11         new Thread(new Printer(‘A‘, n)).start();
 12         new Thread(new Printer(‘B‘, n)).start();
 13         new Thread(new Printer(‘C‘, n)).start();
 14         new Thread(new Printer(‘D‘, n)).start();
 15         scanner.close();
 16     }
 17     
 18     static class Printer implements Runnable
 19     {
 20         //所有的线程操作都需要这把锁,所以必须是静态的,否则就不是同一对象了,锁的作用就没了。
 21         //可以把这个锁理解成synchronize的里面的对象锁
 22         public static Lock lock=new ReentrantLock();
 23         //Condition依赖于锁,并且可以获得多个Condition,能够精准地控制线程
 24         public static Condition conditionA=lock.newCondition();
 25         public static Condition conditionB=lock.newCondition();
 26         public static Condition conditionC=lock.newCondition();
 27         public static Condition conditionD=lock.newCondition();
 28         public static char last=‘D‘;
 29         private char c;
 30         private int n;
 31         public Printer(char c,int n)
 32         {
 33             this.c=c;
 34             this.n=n;
 35         }
 36         @Override
 37         public void run() {
 38             // TODO Auto-generated method stub
 39             switch (c) {
 40             case ‘A‘:
 41                     printA();
 42                 break;
 43             case ‘B‘:
 44                     printB();
 45                 break;
 46             case ‘C‘:
 47                     printC();
 48                 break;
 49             case ‘D‘:
 50                     printD();
 51                 break;
 52             default:
 53                 break;
 54             }
 55         }
 56         
 57         private void printA()
 58         {
 59             for(int i=0;i<n;i++)
 60             {
 61                 lock.lock();
 62                 try {
 63                     if(last!=‘D‘)
 64                     {
 65                         conditionA.await();
 66                     }
 67                     System.out.print(c);//假如当前是D,那么下一个肯定就是A即自身,可以打印了
 68                     last=c;
 69                     conditionB.signal();
 70                 } catch (InterruptedException e) {
 71                     // TODO Auto-generated catch block
 72                     e.printStackTrace();
 73                 }
 74                 finally
 75                 {
 76                     lock.unlock();
 77                 }
 78             }
 79         }
 80         
 81         private void printB()
 82         {
 83             for(int i=0;i<n;i++)
 84             {
 85                 lock.lock();
 86                 try {
 87                     if(last!=‘A‘)
 88                     {
 89                         conditionB.await();
 90                     }
 91                     System.out.print(c);
 92                     last=c;
 93                     conditionC.signal();
 94                 } catch (InterruptedException e) {
 95                     // TODO Auto-generated catch block
 96                     e.printStackTrace();
 97                 }
 98                 finally
 99                 {
100                     lock.unlock();
101                 }
102             }
103         }
104         
105         private void printC()
106         {
107             for(int i=0;i<n;i++)
108             {
109                 lock.lock();
110                 try {
111                     if(last!=‘B‘)
112                     {
113                         conditionC.await();
114                     }
115                     System.out.print(c);
116                     last=c;
117                     conditionD.signal();
118                 } catch (InterruptedException e) {
119                     // TODO Auto-generated catch block
120                     e.printStackTrace();
121                 }
122                 finally
123                 {
124                     lock.unlock();
125                 }
126             }
127         }
128         
129         private void printD()
130         {
131             for(int i=0;i<n;i++)
132             {
133                 lock.lock();
134                 try {
135                     if(last!=‘C‘)
136                     {
137                         conditionD.await();
138                     }
139                     System.out.print(c);
140                     last=c;
141                     conditionA.signal();
142                 } catch (InterruptedException e) {
143                     // TODO Auto-generated catch block
144                     e.printStackTrace();
145                 }
146                 finally
147                 {
148                     lock.unlock();
149                 }
150             }
151         }
152         
153     }
154 }

     需要注意对Condition的理解,Condition不能从名字上判断跟哪个线程相关,比如ConditionA就与AThread相关,这种理解是错的,condition只与lock相关,conditionB.await()不能让BThread阻塞,而只是让当前线程阻塞并放弃锁,进入睡眠等待被唤醒,conditionA.await()的目的是阻塞放弃锁并可以通过conditionA.signal()唤醒(并不是立即唤醒,而是在unlock后)。整个程序的执行过程大概如下:

  假设ABCD四个线程同时执行,线程B发现上一个字母不是B则阻塞释放锁,CD同理,只有A能够运行打印A,然后唤醒B,以此类推,就不断地打印ABCDABCD。

JAVA 多线程开篇 -从按顺序打印ABC开始

标签:

原文地址:http://www.cnblogs.com/maydow/p/4780780.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!