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

jchrr9hc  于 2021-07-13  发布在  Java
关注(0)|答案(9)|浏览(369)

我试图理解倒计时锁的用法,下面是我在这里使用的代码,
可递减.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");
    }
}

倒计时线程.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启动,就应该打印这一行“thread1started”,但是由于cddt thread的cdl.await()语句中的wait语句,主线程被阻塞了。只是想知道这背后的原因是什么?

cl25kdpy

cl25kdpy1#

在你的 CountDownThread 同学们,我想你们想推翻 run() 方法而不是 start 而不是
公共同步void start(){
尝试
public void run(){
为什么
cdl中的wait语句。cddt线程中的await()语句。只是想知道这背后的原因是什么?
在这种情况下,您已经覆盖了 start 方法 Thread 因此它不再像平常那样生成线程来执行代码。
因此,没有线程生成并影响 main 线程正在调用 cd1.await() 而不是 cd1 线程(你想要的)。这就是为什么 main 线程被阻塞。

cgh8pdjw

cgh8pdjw2#

我认为您应该了解线程同步和线程优先级的概念。
1.线程优先级:
java中的每个线程都有一定的优先级—可以是jvm生成的默认优先级,也可以是程序员提供的自定义优先级—线程优先级的有效范围是1到10,其中1是最小优先级,10是最大优先级—thread class定义了以下常量来表示一些标准优先级:
1.thread.min\u优先级

lnvxswe2

lnvxswe23#

-------1
2.thread.norm\u优先级

uqdfh47h

uqdfh47h4#

------5
3.thread.max\u优先级

mlmc2os5

mlmc2os55#

-------10
线程调度程序将在分配处理器时使用优先级具有最高优先级的线程将首先获得机会如果两个线程具有相同的优先级,那么我们不能期望确切的执行顺序它取决于线程调度程序
thread类定义以下方法来获取和设置线程的优先级:
1.public final int getpriority()
2.公共最终无效设置优先级(int p)
note:allowed values 范围从1到10,否则我们将得到运行时异常illegalargumentexception
例如:t.setpriority(7):有效
t、 设置优先级(17):illegalargumentexception

bvjveswy

bvjveswy7#


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

oxiaedzo

oxiaedzo8#

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

qlvxas9a

qlvxas9a9#


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........");
        }

     }
  }

如果我们注解第1行,那么主线程和子线程都具有相同的优先级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.同步:
synchronized是仅适用于方法和块的修饰符,但不适用于类和变量。
如果多个线程试图在同一个java对象上同时操作,那么就有可能出现数据不一致的问题。
为了克服这个问题,我们应该使用synchronized关键字如果一个方法或块声明为synchronized,那么一次只允许一个线程在给定的对象上执行该方法或块,这样数据不一致的问题就会得到解决。
synchronized关键字的主要优点是可以解决数据不一致的问题,但是synchronized关键字的主要缺点是它增加了线程的等待时间,并且会产生性能问题,因此如果没有特定的要求,则不建议使用synchronized关键字。
内部同步的概念是用锁来实现的,java中的每个对象都有一个唯一的锁。
每当我们使用同步关键字,那么只有锁的概念将进入图片。
如果一个线程想首先在给定对象上执行synchronized方法,它必须获得该对象的锁。
一旦线程获得了锁,就可以对该对象执行任何同步方法。
一旦方法执行完成,线程就会自动释放锁。在内部获取和释放锁由jvm和一个不负责此活动的程序员负责
当一个线程在给定对象上执行同步方法时,不允许其余线程在同一对象上同时执行任何同步方法,但允许其余线程同时执行非同步方法
例子:

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()方法,因为它不是同步方法。锁的概念是基于对象实现的,而不是基于方法实现的
注意:记住每个对象都有两个区域:
1.同步区域。
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(字符串名称)方法声明为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中的每个类都有一个唯一的锁,它只不过是类级锁。
如果线程想要执行静态同步方法,那么线程需要类级锁。
一旦线程获得了类级锁,就可以执行该类的任何静态同步方法。
方法执行完成后,当线程执行静态同步方法时,线程自动释放锁,不允许剩余线程同时执行该类的任何静态同步方法,但允许剩余线程同时执行以下方法:
常规静态法。
同步示例方法。
普通示例方法。
例如:

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

   }

相关问题