Monday, March 16, 2015

Java当中的常见同步方法

在进行多线程编程时,难免还要碰到两个问题,那就线程间的互斥与同步:
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步(下文统称为同步)。

线程间的同步方法大体可分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。
用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。内核模式下的方法有:事件,信号量,互斥量。
方法1:使用同步法,该方法的核心在于synchronized (lock) 其中lock必须是一个对象。

public class CriticalSectionSynchronizedBlock
{
 static String message = "Now Is The Time For All Good Men\n";
 static int numThreads = 200;
 
 static Integer lock = 1;

 public static void main(String args[])
 {
  for (int idx = 0; idx < numThreads; idx++) {
   Thread t = new Thread(new StreamPrinter());
   t.start();
  }
 }

 static class StreamPrinter implements Runnable
 {
  @Override
  public void run()
  {
   while (true) {
    byte chars[] = message.getBytes();
    synchronized (lock) {
     for (int idx = 0; idx < chars.length; idx++) {
      byte achar = chars[idx];
      System.out.write((char) achar);
      Thread.yield();
     }
    }
   }
  }
 }
}
方法2: 使用信号灯:Semaphore(1)表示只能运行一个程序,Semaphore(n)可以运行n个线程
public class CriticalSectionSemaphore

{

 static String message = "Now Is The Time For All Good Men\n";

 static int numThreads = 200;



 public static void main(String args[])

 {

  for (int idx = 0; idx < numThreads; idx++) {

   Thread t = new Thread(new StreamPrinter());

   t.start();

  }

 }



 static class StreamPrinter implements Runnable

 {

  static Semaphore sema = new Semaphore(1);



  @Override

  public void run()

  {

   try {

    while (true) {

     byte chars[] = message.getBytes();

     sema.acquire();

     for (int idx = 0; idx < chars.length; idx++) {

      byte achar = chars[idx];

      System.out.write((char) achar);

      Thread.yield();

     }

     sema.release();

    }

   }

   catch (InterruptedException ex) {

    System.err.println(ex.getLocalizedMessage());

   }

  }

 }

}
acquire();表示获取信号 release();表示释放信号
1:  public class CriticalSectionMonitor  
2:  {  
3:       static String message = "Now Is The Time For All Good Men\n";  
4:       static int numThreads = 200;  
5:       static Object monitor = new Object();  
6:       public static void main(String args[])  
7:       {  
8:            for (int idx = 0; idx < numThreads; idx++) {  
9:                 Thread t = new Thread(new StreamPrinter());  
10:                 t.start();  
11:            }  
12:            // Needed to start / unblock the first waiting thread.   
13:            synchronized(monitor) {  
14:                 monitor.notify();  
15:            }  
16:       }  
17:       static class StreamPrinter implements Runnable  
18:       {  
19:            @Override  
20:            public void run()  
21:            {  
22:                 try {  
23:                      while (true) {  
24:                           byte chars[] = message.getBytes();  
25:                           synchronized(monitor) { // Start Critical Section  
26:                                monitor.wait();  
27:                           }  
28:                           for (int idx = 0; idx < chars.length; idx++) {  
29:                                byte achar = chars[idx];  
30:                                System.out.write((char) achar);  
31:                                Thread.yield();  
32:                           }  
33:                           synchronized(monitor) { // End Critical Section  
34:                                monitor.notify();  
35:                           }  
36:                      }  
37:                 }  
38:                 catch (InterruptedException ex) {  
39:                      System.err.println(ex.getLocalizedMessage());  
40:                 }  
41:            }  
42:       }  
43:  }  




方法3:monitor


  1. public class CriticalSectionMonitor
  2. {
  3. static String message = "Now Is The Time For All Good Men\n";
  4. static int numThreads = 200;
  5. static Object monitor = new Object();
  6. public static void main(String args[])
  7. {
  8. for (int idx = 0; idx < numThreads; idx++) {
  9. Thread t = new Thread(new StreamPrinter());
  10. t.start();
  11. }
  12. // Needed to start / unblock the first waiting thread.
  13. synchronized(monitor) {
  14. monitor.notify();
  15. }
  16. }
  17. static class StreamPrinter implements Runnable
  18. {
  19. @Override
  20. public void run()
  21. {
  22. try {
  23. while (true) {
  24. byte chars[] = message.getBytes();
  25. synchronized(monitor) { // Start Critical Section
  26. monitor.wait();
  27. }
  28. for (int idx = 0; idx < chars.length; idx++) {
  29. byte achar = chars[idx];
  30. System.out.write((char) achar);
  31. Thread.yield();
  32. }
  33. synchronized(monitor) { // End Critical Section
  34. monitor.notify();
  35. }
  36. }
  37. }
  38. catch (InterruptedException ex) {
  39. System.err.println(ex.getLocalizedMessage());
  40. }
  41. }
  42. }
  43. }


注意下面两个例子中的错误,第一个是是没有同步方法,第二个是同步错误,该class使用同步方法,但是没有静态化,所以200个线程只是锁定了自己的方法,同步没有达到该有的效果。
  1. public class CriticalSectionBroken
  2. {
  3. static String message = "Now Is The Time For All Good Men\n";
  4. static int numThreads = 200;
  5. public static void main(String args[])
  6. {
  7. for (int idx = 0; idx < numThreads; idx++) {
  8. Thread t = new Thread(new StreamPrinter());
  9. t.start();
  10. }
  11. }
  12. static class StreamPrinter implements Runnable
  13. {
  14. @Override
  15. public void run()
  16. {
  17. while (true) {
  18. byte chars[] = message.getBytes();
  19. for (int idx = 0; idx < chars.length; idx++) {
  20. byte achar = chars[idx];
  21. System.out.write((char) achar);
  22. Thread.yield();
  23. }
  24. }
  25. }
  26. }
  27. }
  1. public class CriticalSectionFailedSynchronize
  2. {
  3. static String message = "Now Is The Time For All Good Men\n";
  4. static int numThreads = 200;
  5. public static void main(String args[])
  6. {
  7. for (int idx = 0; idx < numThreads; idx++) {
  8. Thread t = new Thread(new StreamPrinter());
  9. t.start();
  10. }
  11. }
  12. static class StreamPrinter implements Runnable
  13. {
  14. @Override
  15. public void run()
  16. {
  17. while (true) {
  18. printMessage();
  19. }
  20. }
  21. private synchronized void printMessage()
  22. {
  23. byte chars[] = message.getBytes();
  24. for (int idx = 0; idx < chars.length; idx++) {
  25. byte achar = chars[idx];
  26. System.out.write((char) achar);
  27. Thread.yield();
  28. }
  29. }
  30. }
  31. }

No comments:

Post a Comment