thread

1   Thread

1.1 introductions

java.lang
类 Thread

java.lang.Object
  java.lang.Thread

所有已实现的接口:

Runnable

public class Thread

extends Object

implements Runnable

线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:

1.调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。

2.非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。

创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。例如,计算大于某一规定值的质数的线程可以写成:

 class PrimeThreadextends Thread {                                     

         longminPrime;

        PrimeThread(long minPrime) {

            this.minPrime = minPrime;

         }

 

         public voidrun() {

             //compute primes larger than minPrime

             . . .

         }

     }

然后,下列代码会创建并启动一个线程:

PrimeThreadp = new PrimeThread(143);

     p.start();

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:

classPrimeRun implements Runnable {

         long minPrime;

         PrimeRun(long minPrime) {

             this.minPrime = minPrime;

         }

 

         public void run() {

             // compute primes larger thanminPrime

              . . .

         }

     }

然后,下列代码会创建并启动一个线程:

PrimeRunp = new PrimeRun(143);

     new Thread(p).start();

每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。

从以下版本开始:JDK1.0

另请参见:Runnable, Runtime.exit(int), run(), stop()

 

static Thread

currentThread()
          返回对当前正在执行的线程对象的引用。

 String

getName()
          返回该线程的名称。

 int

getPriority()
          返回线程的优先级。

 void

run()
          如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

static void

sleep(long millis)
          在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

 void

start()
          使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

 String

toString()
          返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

static void

yield()
          暂停当前正在执行的线程对象,并执行其他线程。

void

setDaemon(boolean on)
          将该线程标记为守护线程或用户线程。

1.2 example

1.2.1   customizedThread

public class MyThread extends Thread{

   public void run() {

      for(int i=0;i<100;i++){

         System.out.println(i);

      }

   }

}

1.2.2   test

public static void main(String[] args){

      MyThread myThread1=new MyThread();

      //启动线程

      myThread1.setName("hah");

      myThread1.start();

      MyThread myThread2=new MyThread();

      myThread2.setName("线程2");

      myThread2.start();

       //Thread的currentThread()方法可以得到当前线程的对象

      Thread.currentThread().setName("Main");

      for(int i=0;i<100;i++){

         System.out.println(Thread.currentThread().getName()+"---"+i);

      }

   }

   @Test

   //如果在test里面测试,会受到test线程的影响,不能饱和执行线程。

   public void testMyThread(){

      MyThread myThread=new MyThread();

      //启动线程

      myThread.setName("线程1");

      myThread.start();

      MyThread myThread1=new MyThread();

      myThread1.setName("线程2");

      myThread1.start();

   }

2   Runnable

2.1 introduction

java.lang
接口 Runnable

所有已知子接口:

RunnableFuture<V>,RunnableScheduledFuture<V>

所有已知实现类:

AsyncBoxView.ChildState, FutureTask, RenderableImageProducer, SwingWorker, Thread, TimerTask

public interface Runnable

Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。

设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread 类实现了 Runnable。激活的意思是说某个线程已启动并且尚未停止。

此外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。

从以下版本开始: JDK1.0

另请参见: Thread, Callable

2.2 使用Runnable接口实现类的底层原理

(1).Thread类实现自Runnable接口,且包含属性Runnable target。

Publicclass Thread implements Runnable {

    private int            priority;

    private Thread         threadQ;

private long           eetop;

....

private Runnable target;

}

(2).Runnable接口只有一个抽象方法

 void

run()
          使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。

(3).Thread类本身的run方法源码,也是执行了自身Runnable属性的run方法。而采用继承Thread类创建线程子类的方式,是重写了这个run方法。重点代码见标红。

public void run() {

        if (target != null) {

            target.run();

        }

    }

(4).Thread的传Runnable实例的构造方法源码。利用多态的特征,将实现了Runnable接口的类赋值给Thread自身的Runnable属性,从而调用的run方法就是实现类的run方法。

public Thread(Runnable target, String name) {

        init(null, target, name, 0);

}

private void init(ThreadGroup g, Runnable target, String name,

                      long stackSize) {

        init(g, target, name, stackSize, null);

}

private void init(ThreadGroup g, Runnable target, String name,

                      long stackSize,AccessControlContext acc) {

        if (name == null) {

            throw newNullPointerException("name cannot be null");

        }

        this.name = name.toCharArray();

        Thread parent = currentThread();

        SecurityManager security = System.getSecurityManager();

        if (g == null) {

            if (security != null) {

                g = security.getThreadGroup();

            }

            if (g == null) {

                g = parent.getThreadGroup();

            }

        }

        g.checkAccess();

        if (security != null) {

            if (isCCLOverridden(getClass())){

                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);

            }

        }

        g.addUnstarted();

        this.group = g;

        this.daemon = parent.isDaemon();

        this.priority = parent.getPriority();

        if (security == null || isCCLOverridden(parent.getClass()))

            this.contextClassLoader = parent.getContextClassLoader();

        else

            this.contextClassLoader = parent.contextClassLoader;

        this.inheritedAccessControlContext =

                acc != null ? acc :AccessController.getContext();

        this.target = target;

        setPriority(priority);

        if (parent.inheritableThreadLocals != null)

            this.inheritableThreadLocals =

                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

        this.stackSize = stackSize;

        tid = nextThreadID();

    }

2.3 example

2.3.1   Runnable实现类

public class MyRunnable implements Runnable{

   public void run() {

      for(int i=0;i<100;i++){

         System.out.println(Thread.currentThread().getName()+"---"+i);

      }

   }

}

2.3.2   test

public static void main(String[] args){

      //创建任务对象

      MyRunnable myrun=new MyRunnable();

      //通过Thread类的构造方法分配新的Thread对象

      Thread t1=new Thread(myrun,"run1");

      Thread t2=new Thread(myrun,"run2");

      Thread t3=new Thread(myrun,"run3");

      t1.start();

      t2.start();

      t3.start();

   }

 

3   Thread类的启动原理

run:用来封装线程任务的,无法启动线程

start:先启动线程,再调用run方法。

Threadl类的start方法源码,主要是调用了start0方法。而start0方法是native修饰的,也就是调用了一个非java代码的接口。由于启动线程涉及到jvm,所以这里的启动过程可能有c或者其他语言来实现的。重点代码标红。与这个问题相关的知识是,jvm是用c和汇编等语言开发的。在底层的要看start0方法所关联的c代码等了。

public synchronized void start() {

        if (threadStatus != 0)

            throw newIllegalThreadStateException();

        group.add(this);

        boolean started = false;

        try {

            start0();

            started = true;

        } finally {

            try {

                if (!started) {

                    group.threadStartFailed(this);

                }

            } catch (Throwable ignore) {

            }

        }

}

private native void start0();

4   Thread常用的方法

 void

setPriority(int newPriority)
          更改线程的优先级。

同样的,在底层源码中,setPriority方法中调用了native的setPriority0的方法。

static void

sleep(long millis)
          在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

Sleep属于静态方法,需要用类调用。

public void run() {

      for(int i=0;i<100;i++){

         try {

            Thread.sleep(100);

            System.out.println(Thread.currentThread().getName()+"--"+i);

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

      }

   }

 

 void

join(long millis)
          等待该线程终止的时间最长为 millis 毫秒。

 

static void

yield()
          暂停当前正在执行的线程对象,并执行其他线程。

Yield属于静态方法,需要用类调用。

public void run() {

      for(int i=0;i<100;i++){

         System.out.println(Thread.currentThread().getName()+"--"+i);

         Thread.yield();

      }

   }

 

 void

setDaemon(boolean on)
          将该线程标记为守护线程或用户线程。

setDaemon方法必须在启动线程前调用。

public static void main(String[] args){

      //创建任务对象

      MyRunnable myrun=new MyRunnable();

      SleepTask st=new SleepTask();

      YieldTask yt=new YieldTask();

      //通过Thread类的构造方法分配新的Thread对象

      Thread t1=new Thread(myrun,"run1");

      Thread t2=new Thread(myrun,"run2");

      Thread t3=new Thread(myrun,"run3");

      Thread t4=new Thread(st,"runsleep");

      Thread t5=new Thread(yt,"runyield");

      t1.start();

      //t1.start();

      try {

         t1.join(4);

      } catch (InterruptedException e) {

         e.printStackTrace();

      }

      t2.start();

      t3.start();

      t5.setDaemon(true);

      t5.start();

      //t4.start();

      ThreadGroup tg=t2.getThreadGroup();

      System.out.println(tg);

      Thread.State ts=t2.getState();

      System.out.println(ts);

      //设置线程的优先级

      t1.setPriority(1);

      t2.setPriority(10);

   }

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值