为什么主线程在启动第一个线程后正在等待?

时间:2016-03-28 05:20:46

标签: java java.util.concurrent countdownlatch

我试图了解CountDownLatch用法,以下是我在这里使用的代码,

DecrementRunnable.java

    package com.nirjhar.java.countdownlatchexample;

    import java.util.concurrent.CountDownLatch;

    public class DecrementRunnable implements Runnable {

    private String name;
    private CountDownLatch cdl;

    public DecrementRunnable(String name, CountDownLatch cdl) {
    this.name=name;
    this.cdl=cdl;
    }

    @Override
    public void run() {
        System.out.println("in run method");
    for (int i = 0; i < 6; i++) {
        cdl.countDown();
        System.out.println("counting down "+cdl.getCount());
    }
    //cdl.notifyAll();
    System.out.println("Notified to all");
    }
}

CountDownDemoThread.java

package com.nirjhar.java.countdownlatchexample;

import java.util.concurrent.CountDownLatch;

public class CountDownDemoThread extends Thread {

    private CountDownLatch cdl;

    public CountDownDemoThread(String name, CountDownLatch cdl) {
        this.cdl=cdl;
        setName(name);
    }

    @Override
    public synchronized void start() {

        System.out.println("Task completed ... waiting for other thread to complete their task");
        try {
            cdl.await();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
        System.out.println("Continuing my tasks ..");
    }
}

主程序

package com.nirjhar.java.countdownlatchexample;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args)
    {
        CountDownLatch cdl=new CountDownLatch(6);
        Thread tDecrementThread=new Thread(new DecrementRunnable("Runnable", cdl));
        CountDownDemoThread cddt=new CountDownDemoThread("thread", cdl);        
        cddt.start();   
        System.out.println("thread 1 started");     
        tDecrementThread.start();
    }
}

在这个主程序中,我希望一旦启动线程1,这行“线程1启动”应该被打印,但是由于cddt线程中cdl.await()语句中的wait语句,这里主线程被阻塞。只是想知道这背后的原因是什么?

2 个答案:

答案 0 :(得分:3)

CountDownThread课程中,我认为您要覆盖run()方法,而不是start

而不是

  

public synchronized void start(){

尝试

  

public void run(){

原因

  cddt thread中的cdl.await()语句中的

wait语句。只是想知道这背后的原因是什么?

在这种情况下,您已覆盖start的{​​{1}}方法,因此它不再像正常情况那样生成执行代码的线程。

因此没有产生线程,事实上Thread线程正在调用main而不是cd1.await()线程(你想要的)。这就是cd1线程被阻止的原因。

答案 1 :(得分:0)

我认为你应该经历线程同步和线程优先级的概念。

1.Treread Priority:

java中的每个线程都有一些优先级,它可能是由jvm生成的默认优先级或程序员提供的自定义优先级 线程优先级的有效范围是1到10,其中1是最小优先级,10是最大优先级 Thread类定义了以下常量来表示一些标准优先级:

1.Thread.MIN_PRIORITY --------------- 1

2.Thread.NORM_PRIORITY ------------ 5

3.Thread.MAX_PRIORITY ------------- 10

线程调度程序将在分配处理器时使用优先级,具有最高优先级的线程将首先获得机会 如果两个线程具有相同的优先级,那么我们不能指望精确的执行顺序,它取决于线程调度程序

Thread类定义了以下获取和设置线程优先级的方法:

1.public final int getPriority()

2.public final void setPriority(int p)

注意:允许的值范围为1到10,否则我们将获得运行时异常IllegalArgumentException

Ex:t.setPriority(7):有效

t.setPriority(17):抛出:IllegalArgumentException

----------------------------------------默认优先级----- ---------------------------------

仅主线程的默认优先级为5,但对于所有剩余线程,默认优先级将从父级继承到子级,即父级线程具有相同优先级的任何优先级将存在于子线程

--------------------------自定义优先级------------------- ------------------------------

   class Mythread extends Thread
      {
        public void run()
        {
          for(int i=0;i<=5;i++)
          {
           System.out.println("child thread........");
           }
       }

     }
  public class ThreadDemo
   {
  public static void main(String arg[])
  {
      Mythread t=new Mythread();
     //   t.setPriority(10);----------(1)
      t.start();

       for(int i=0;i<=5;i++)
        {
           System.out.println("main thread........");
        }

     }
  }

如果我们正在评论第一行,那么主线程和子线程都具有相同的优先级5,因此我们不能指望执行顺序和精确输出 如果没有注释第1行,那么主线程的优先级为5,子线程具有优先级,因此子线程将首先获得机会,然后是主线程,在这种情况下输出为:

    Child thread……….

    Child thread……….

    Child thread……….

    Child thread……….

    Child thread……….

    Main thread……….

    Main thread……….

    Main thread……….

    Main thread……….

    Main thread……….

   [NOTE: some platforms won’t provide proper support for thread priority]

2.Synchronization:

Synchronized是仅适用于方法和块的修饰符,但不适用于类和变量。

如果多个线程试图在同一个java对象上同时运行,那么可能存在数据不一致问题。

为了克服这个问题,我们应该使用synchronized关键字,如果一个方法或块声明为synchronized,那么一次只允许一个线程在给定对象上执行该方法或块,以便解决数据不一致问题。 / p>

synchronized关键字的主要优点是我们可以解决数据不一致问题但是synchronized关键字的主要缺点是它增加了线程的等待时间并且它产生了性能问题因此如果没有特定要求则不建议使用synchronized关键字。

内部同步概念是通过使用lock实现的,java中的每个对象都有一个唯一的锁。

每当我们使用synchronized关键字时,只会出现锁定概念。

如果线程想要首先对给定对象执行synchronized方法,则必须锁定该对象。

一旦线程获得锁定,就可以在该对象上执行任何同步方法。

一旦方法执行完成,线程释放就会自动锁定。内部获取和释放锁定由jvm和不负责此活动的程序员负责

当一个线程在给定对象上执行synchronized方法时,不允许其余线程同时在同一个对象上执行任何同步方法,但允许剩余线程同时执行非同步方法

示例:

Class X
{
  synchronized void m1() {}
  synchronized void m2() {}
   public void m3(){}


  }

在上面的例子中假设线程T1开始执行m1(),因为T1访问首先从jvm锁定,如果在同一时间线程T2来执行m1()方法并且线程T3来执行m2()方法,那时间线程T2和T3都将处于等待状态,直到T1线程释放锁定。

如果线程T4执行m3()方法,它将直接执行方法m3(),因为它不是synchronized方法。 锁概念是基于对象实现的,而不是基于方法

注意:请记住每个对象有两个区域:

1.Synchronized area。

2.非同步区域。

 Class X 

{

   Synchronized();

{

   Where ever we are performing update operation           
  ( Add/remove/delete/replace).

   That is  Where state of object changing.

}

 Non-synchronized()

{

  Where ever state of object won’t be changed, like only read    
 operation is performed.


  }



 }

示例:程序化方法:

  class Display{

    public synchronized void wish(String name){

        for(int i=1;i<=5;i++){
           System.out.print("Good Morning:");

            try{
                 Thread.sleep(2000);
              }

            catch(InterruptedException e){
                 System.out.println("i got Interrupted");

              }

                  System.out.println(name);
          }

      }

}


  class ThreadDemo extends Thread
   {

     Display d;
     String name;
  public ThreadDemo(Display d,String name){

           this.d=d;
           this.name=name;

        }
  public void run(){
         d.wish(name);
      }


}


public class SynchronizedDemo

{

    public static void main(String arg[]){

         Display d=new Display();
         ThreadDemo t1=new ThreadDemo(d,"Avadhoot");
         ThreadDemo t2=new ThreadDemo(d,"Abhishek");
         ThreadDemo t3=new ThreadDemo(d,"Rinkesh");
         ThreadDemo t4=new ThreadDemo(d,"Kushal");
         t1.start();
         t2.start();
         t3.start();
         t4.start();
    }


}

[注意:如果我们没有将wish(String name)方法声明为synchronized,那么所有线程将同时执行,因此我们将得到不规则的输出。

如果我们将wish(String name)方法声明为synchronized,那么一次只允许一个线程在给定的Display(class)对象上执行wish(String name)方法,因此我们将得到常规输出。]

案例研究:

 public class SynchronizedDemo

 {

     public static void main(String arg[])

     {        
            Display d1=new Display();
            Display d2=new Display();
            Display d3=new Display();
            Display d4=new Display();
         ThreadDemo t1=new ThreadDemo(d1,"Avadhoot");
         ThreadDemo t2=new ThreadDemo(d2,"Abhishek");
         ThreadDemo t3=new ThreadDemo(d3,"Rinkesh");
         ThreadDemo t4=new ThreadDemo(d4,"Kushal");
         t1.start();
         t2.start();
         t3.start();
         t4.start();

     }

  }

即使wish(String name)方法已同步,我们也会得到不规则输出,因为线程在不同的java对象上运行

结论:

如果多个线程在同一个java对象上运行,则需要同步。

如果多个线程在多个java对象上运行,则不需要同步。

*班级锁定:

java中的每个类都有一个唯一的锁,它只是类级锁。

如果线程想要执行静态同步方法,则线程需要类级锁定。

一旦线程得到类级别锁定,就允许它执行该类的任何静态同步方法。

一旦方法执行完成,线程释放就会自动锁定 在执行静态同步方法的线程中,不允许其余线程同时执行该类的任何静态同步方法,但允许剩余线程同时执行以下方法:

  1. 普通静态方法。

  2. 同步实例方法。

  3. 普通实例方法。

  4. 例如:

       Class X
        {
         static synchronized m1(){}
         static synchronized m2(){}
         static m3(){}
         synchronized m4(){}
        m5(){}
    
       }