简体   繁体   English

Java中的线程同步

[英]Threads synchronization in Java

I have a scenario like.... There are four threads named as Thread1, Thread2, Thread3 and Thread4. 我有一个类似的场景。...有四个线程分别命名为Thread1,Thread2,Thread3和Thread4。 and there is one counter variable. 并且有一个计数器变量。 And I want output as below 我想输出如下

Thread1 : value of counter variable is = 0
Thread2 : value of counter variable is = 1
Thread3 : value of counter variable is = 2
Thread4 : value of counter variable is = 3

Thread1 : value of counter variable is = 4
Thread2 : value of counter variable is = 5
Thread3 : value of counter variable is = 6
Thread4 : value of counter variable is = 7

Thread1 : value of counter variable is = 8
Thread2 : value of counter variable is = 9
Thread3 : value of counter variable is = 10
Thread4 : value of counter variable is = 11

Even I have done this by logically. 甚至我在逻辑上也做到了。 But I want something like, When Thread1 is printing the variable of counter then all the remaining threads should wait.....then after Thread2 should come to the picture and print the counter variable and rest should wait. 但是我想要类似的东西,当Thread1正在打印counter变量时,所有其余线程都应等待.....然后在Thread2之后出现图片并打印counter变量,其余应等待。

Suggest me the best solution for this. 建议我为此的最佳解决方案。 Thanks in advance :-) 提前致谢 :-)

There is little sense in this, except for understanding synchronization. 除了了解同步,这几乎没有意义。 I'd use a CyclicBarrier to do this. 我会使用CyclicBarrier来做到这一点。 It's a rather high level abstraction, so you don't have to use wait() or notifiy() by yourself. 这是一个相当高级的抽象,因此您不必自己使用wait()notifiy()

Alternatively, you could use an Integer or AtomicInteger object as variable and pass it around the threads (each one should provide a consume(Integer i) method which can be called by another thread, then increments and prints the value and passes it to the next thread in the ring). 或者,您可以使用IntegerAtomicInteger对象作为变量,并将其传递到线程周围(每个对象都应提供可被另一个线程调用的consume(Integer i)方法,然后递增并打印该值并将其传递给下一个螺纹)。 In this variant, the synchronization is handled implicit within your code. 在此变体中,同步在代码中隐式处理。

I'm not sure what do you want. 我不确定你想要什么。 Do you want your threads to increment and print variable in order ? 您是否要让线程按顺序增加并打印变量? It doesn't make sense, threads are independent and are running concurrently . 这没有任何意义,线程是独立的,并且可以同时运行。 That's what they are for. 那就是他们的目的。

So let me get this straight: you want to use parallel processing to do serial work. 因此,让我直接讲:您想使用并行处理来进行串行工作。

Basically what you want to do is this: 基本上,您要做的是:

for(int i=0;i<10;i++)
    System.out.println(i);

but then with threads. 但是然后有线程。

Threads are used to do things in parallel. 线程用于并行处理事务。 That is what they are for. 那就是他们的目的。 Trying to force a serial problem into this concept will not only slow down your application but also make it much more error prone. 试图将串行问题强加给这个概念,不仅会减慢您的应用程序的速度,而且会使它更容易出错。

Unless, of course, this example of yours is very much simplified. 当然,除非您的这个示例非常简化。 Maybe you need to give some more information for us to be able to help, then... 也许您需要提供更多信息以帮助我们,然后...

This is an interesting problem, since threads are designed to work side by side independently, rather than locked into a strict order. 这是一个有趣的问题,因为线程被设计为独立地并排工作,而不是严格地锁定在一起。

I think the simplest way to achieve this is with a fair ReentrantLock , an AtomicInteger and some cautious setup (to ensure that the threads start waiting on the ReentrantLock in the correct order). 我认为最简单的方法是使用公平的ReentrantLockAtomicInteger和一些谨慎的设置(以确保线程以正确的顺序开始在ReentrantLock上等待)。

Your main thread will need to initialise the counter, create the lock object and lock it, then start the four child threads in order, ensuring each of them arrives at the lock before setting the next thread off. 您的主线程将需要初始化计数器,创建锁对象并对其进行锁定,然后依次启动四个子线程,确保在关闭下一个线程之前,每个子线程都到达了锁。

When all 4 threads are primed, you can release the lock and let the other threads run. 当所有4个线程准备就绪时,您可以释放锁并让其他线程运行。

Each worker thread should grab the value from the counter, increment it, display the counter, then release the lock (which will let the next thread run) before reacquiring it. 每个工作线程应从计数器中获取值,将其递增,显示计数器,然后释放锁(这将使下一个线程运行),然后再重新获取它。

Note that there is still a race condition here: Thread 2 could race round the loop before Thread 1 starts waiting for the lock again, and so the two threads would end up running in inverted order. 请注意,这里仍然存在竞争条件:线程2可能在线程1开始再次等待锁之前绕循环运行,因此这两个线程最终将以相反的顺序运行。 To fix this, the worker threads need to wait until enough other threads are waiting until they proceed around the loop (except of course for the final iteration). 要解决此问题,辅助线程需要等待,直到有足够多其他线程在等待,直到它们在循环中继续进行为止(当然,最后一次迭代除外)。 Not nice, but I fear essential given the listed constraints. 不太好,但是由于列出的限制,我担心这很重要。

This is not simple code. 这不是简单的代码。 The lesson to be learned here, I think, is that you shouldn't really use multiple threads to perform inherently serial work! 我认为,这里要学习的教训是,您不应该真正使用多个线程来执行固有的串行工作! Either that, or you shouldn't care exactly which thread performs which of the serial operations. 要么,要么您不必在乎哪个线程执行哪个串行操作。

I have found two ways for this problem.... but still waiting for experts comments.... 我找到了解决此问题的两种方法。...但仍在等待专家评论...。

First way :----- 第一种方式:-----

package semafore; 包semafore;

import java.util.concurrent.Semaphore; 导入java.util.concurrent.Semaphore;

public class Main { public static void main(String args[]) throws Exception { Semaphore sem = new Semaphore(1, true); 公共类Main {公共静态void main(String args [])引发异常{Semaphore sem = new Semaphore(1,true); Thread thrdA = new Thread(new SyncOutput(sem, "Thread1")); 线程thrdA = new Thread(new SyncOutput(sem,“ Thread1”)); Thread thrdB = new Thread(new SyncOutput(sem, "Thread2")); 线程thrdB = new Thread(new SyncOutput(sem,“ Thread2”)); Thread thrdC = new Thread(new SyncOutput(sem, "Thread3")); 线程thrdC =新线程(新SyncOutput(sem,“ Thread3”)); Thread thrdD = new Thread(new SyncOutput(sem, "Thread4")); 线程thrdD =新线程(新SyncOutput(sem,“ Thread4”));

    thrdA.start();
    thrdB.start();
    thrdC.start();
    thrdD.start();

    thrdA.join();
    thrdB.join();
    thrdC.join();
    thrdD.join();

}

} }

class SyncOutput implements Runnable { Semaphore sem; SyncOutput类实现Runnable {Semaphore sem; String msg; 字符串味精; private static int val = 0; 私有静态int val = 0;

SyncOutput(Semaphore s, String m) {
    sem = s;
    msg = m;
}

public void run() {
    for (int i = 0; i < 3; i++){
        try {
            sem.acquire(1);
            System.out.println(msg + " : " + ++val);
            Thread.sleep(1000);
        } catch (Exception exc) {
            System.out.println("Error Writing File");
        }
    sem.release(1);
    }
}

} }

Second way :----- 第二种方式:-----

package thread; 包线程;

 class num {
         // state variable identifying whose turn it is.
         private String whoseTurn ="A";
         private int cnt=0;

  public  boolean writenum(String who) {

           String x = Thread.currentThread().getName();
                try{
                    Thread.sleep(1000);
                }catch(Exception e){}
          if (x.equalsIgnoreCase(whoseTurn)) {
              System.out.println(x+":"+cnt++);
              if(x.equalsIgnoreCase("A"))
                whoseTurn = "B";
              else if(x.equalsIgnoreCase("B"))
                    whoseTurn = "C";
              else if( x.equalsIgnoreCase("C"))
                    whoseTurn = "D";
              else if( x.equalsIgnoreCase("D"))
                    whoseTurn = "A";

          }
          return true; 
     }
  }


public class Game {

    public static void main(String args[]) {
        num ob = new num();
        Thread A = new Thread(new Player("A", ob));
         Thread B   = new Thread(new Player("B", ob));
        Thread C   = new Thread(new Player("C", ob));
        Thread D   = new Thread(new Player("D", ob));

    A.setName("A");
    B.setName("B");
    C.setName("C");
    D.setName("D");
   A.start();   
   B.start();  
   C.start();
   D.start();
   try {
       // Wait 5 seconds
       Thread.currentThread().sleep(5000);
   } catch (InterruptedException e) { }

   ob.writenum("DONE"); // cause the players to quit their threads.
   try {
       Thread.currentThread().sleep(100);
   } catch (InterruptedException e) { }
   }

} }

class Player implements Runnable {
       num area;   // Table where they play
       String who;

       public Player(String who, num area) {
           this.area  = area;
          this.who = who;
       }

      public void run() {
      while (area.writenum(who));

      }
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM