Java 并发/多线程教程(七)-创建和启动java线程

      本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获。由于个人水平有限,不对之处还望矫正!

创建和启动线程

在java中创建一个线程如下:

Thread thread = new Thread();

调用方法start()来启动一个线程:

thread.start();

        这个例子没有指定线程执行任何代码,线程将会在启动之后停止。

        有两种方式指定线程应该执行什么代码。第一种方式就是创建一个Thread的子类并覆写run()方法。第二种方式就是创建一个实现Runnable接口的类。

Thread的子类

      第一种方式指定线程执行什么样的代码,就是创建一个Thread的子类,并且覆写run()方法。在run()方法里的代码就是你调用start()方法后,线程要执行的代码。下面是一个创建Thread子类的例子:

public class MyThread extends Thread{

       @Override

        public void run(){

             System.out.println("MyThread running");

        }

}

为了创建并启动上面的线程,你应该这样做:

MyThread myThread = new MyThread();

myThread.start();

start()方法会在线程开始后立马返回,而不是等到run()方法执行完毕。当run()执行时,就会输出“MyThread running”;

当然,你也可以创建一个Thread的匿名子类,如下:

Thread thread = new Thread(){

      @Override

       public void run(){

                System.out.println("Thread Running");

       }

}

thread.start();

上面的例子当线程被调用时会输出文本“Thread Running".

实现Runnable接口

     第二种方式指定线程应该执行什么样的代码,就是创建一个实现java.lang.Runnable接口的类。这个Runnable对象可以被Thread执行。

     下面是一个实现了Runnable接口的例子:

public class MyRunnable implements Runnable{

      @Override

      public void run(){

            System.out.println("MyRunnable running");

      }

}

因为有了Thread线程执行的run()方法,将MyRunnable的一个实例传给Thread的构造方法。

Thread thread = new Thread(new MyRunnable());

thread.start();

    当线程启动时,会调用MyRunnable实例中的run()方法,而不是Thread自己的run()方法。上面的例子会输出”MyRunnable running".

当然,你也可以创建一个匿名的Runnable接口实例:

Runnable myRunnable = new Runnable(){

        @Override

        public void run(){

               System.out.println("Runnable running");

         }

}

Thread thread = new Thread(myRunnable);

thread.start();

Subclass or Runnable?

       没有明确的规则说这两种方式哪一种是最好的。个人倾向于实现Runnable接口。将实现Runable接口的一个实例交给Thread的实例。当由线程池来执行实现Runnable接口的线程实例时,当线程池没有空闲线程可以调试时,可以让这些线程很好的排队。但是如果执行的是实现Thread的子类的线程实例,那么将会很难做到这一点。

       有时,你可能要同时实现Runnable和Thread子类。例如:创建一个Thread的线程可以执行一个或多个Runable实例,这就是线程池的实现方式。

常见的陷阱:调用run()方法而不是start()方法

      当创建和启动一个线程,通常会犯的一个错误就是调用run()方法,而不是start()方法,如下:

Thread newThread = new Thread(MyRunnable());

newThread.run(); // should be start();

起初,你可能没有注意到什么,因为run()正如你期待的那样被执行了。然而,他并不是被你刚创建的线程所执行。而是被创建线程的线程执行。换句话说,就是执行上面两行代码的线程来执行的run()里的方法。调用线程的使用start()方法。

线程名称

       当你创建一个线程时,你可以给这个线程指定名称。线程名可以让你和其他的线程进行区分。举个例子:

Thread thread = new Thread("New Thread"){

       @override

       public void run(){

              System.out.println("run by:"+getName());

      }

}

thread.start();

System.out.println(thread.getName());

注意,字符串“New Thread"作为一个参数传给Thread的构造器,这个字符串就是线程的名称,这个名称可以通过方法getName()来获取到,你也可以传递参数的方式给一个实现Runnable的接口的线程指定线程名称:如下

MyRunnable runnable = new MyRunnable();

Thread thread = new Thread(runnable,"New Thread");

thread.start();

System.out.println(thread.getName());

注意。MyRunnable不是Thread的一个子类,他不能直接调用Thread的getName()方法。

Thread.currentThread()

Thread.currentThread()方法返回线程正在执行的线程。

Thread thread = Thread.currentThread();

只要获取到当前运行线程,你就可以在此基础上进行方法的调用。例如:你可以获取到当前正在执行线程的名称。

String threadName = Thread.currentThread().getName();

Java Thread example

这里有一个小例子。首先输出执行main方法的线程名称。这个线程是由JVM指定的。然后开启10个线程,并以”“+i作为他们的线程名。每个线程输出他们的名字后,然后停止。

public class ThreadExample{

     public static void main(String[] args){

           System.out.println(Thread.currentThread().getName());

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

              new Thread(""+i){

                   public void run(){

                       System.out.println("Thread:"+getName()+"running");

                   }

             }.start();

         }

      }

}

注意。线程并不是有序执行的。也就是说线程1并不是第一个执行的线程,这是因为线程的执行原则是并行的,而不是有序的,JVM和操作系统决线程的调度顺序。当他们调度时顺序是不固定的。

时间: 2024-08-31 00:32:12

Java 并发/多线程教程(七)-创建和启动java线程的相关文章

Java 并发/多线程教程(十二)-JAVA同步块

本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正! 一个Java同步块标记一个方法或一个代码块作为同步.可以使用Java同步块来避免竞态条件. java同步关键字       在Java中同步的块被标记为Synchronized关键字.Java中的同步块在某些对象上是同步的.在同一对象上同步的所有同步块只能在同一时间内执行一个线程.所有试图进入同步块的其他线程都被阻塞,直到同步块中的线程退出该块. Synchronized关键字可以

Java 并发/多线程教程(四)-并发模型

       本系列译自jakob jenkov的Java并发多线程教程(本章节部分内容参考http://ifeve.com/并发编程模型),个人觉得很有收获.由于个人水平有限,不对之处还望矫正!        并发系统可以有多种并发模型来实现,并发模型指定线程如何协同完成分配给他们的任务.不同的并发模型以不同的方式划分任务,并且线程与线程之间以不同的方式进行通信和协作. 并发模型与分布式系统的相似性          本文中描述的并发模型类似于分布式系统中使用的不同体系结构.在并发系统中,不同

Java 并发/多线程教程(十一)-JAVA内存模型

本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!         Java内存模型指定Java虚拟机如何与计算机的内存(RAM)一起工作.Java虚拟机是整个计算机的一个模型,所以这个模型自然包含了一个内存模型--也就是Java内存模型.         如果您想要设计正确的并发程序,那么理解Java内存模型是非常重要的.Java内存模型指定了不同线程如何以及何时可以看到由其他线程写入共享变量的值,以及在必要时如何同步访问共享变量

Java 并发/多线程教程(十)-线程安全及不可变性

本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!        只有在多个线程访问相同的资源时,才会出现竞态条件,并且一个或多个线对相同的资源进操作.如果多个线程读取相同的资源条件,就不会发生这种情况.        我们通过使共享变量不可以变来确保共享变量不被别的线程修改,因此这样的共享变量是线程安全的,下面有个例子: public class ImmutableValue{       private int value =

Java 并发/多线程教程(九)-线程安全和共享资源

         本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!       代码被多个线程同时调用是安全的,那么就称之为线程安全.如果一段代码是线程安全的,那么它没有竞态条件.竞态条件只有发生在多个线程更新共享资源.因些,清楚的知道线程执行时什么资源是共享的非常重要. 本地变量        本地变量存储在每个线程自己的栈里,这就意味着本地变量从不与其他线程共享.也就是说本地变量是线程安全的,下面是关于线程安全的本地变量的一个

Java 并发/多线程教程(三)-多线程的开销

        本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!     应用程序由单线程到多线程,不仅仅给我带来了便利,同时也也带来了一些开销.不要因为你会多线程,就把所有的程序都设计成多线程.如果把单线程改成多线程,你获得到的好处要远远超过开销,对于这一点你应该有个清醒的认识.当你犹豫是应该用多线程还是单线程时,你要衡量性能和响应时间,而不是靠猜测. 更复杂的设计 尽管多线程应用程序的某些部分比单线程应用程序更简单,但其他部分

Java 并发/多线程教程(二)-多线程的优点

        本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!      尽管多线程有诸多的挑战,但是多线程被广泛使用的原因有以下几点: 1.对资源的充分利用. 2.简化程序设计 3.响应的及时性 资源的充分利用        假设一个应用程序从本地文件系统中读取并处理一个文件,让我们来假设从硬盘读取文件需要5秒,处理文件需要两秒,那么处理两个文件则需要: 5秒 读取A文件 2秒 处理A文件 5秒 读取B文件 2秒 处理B文件

Java 并发/多线程教程(五)-相同线程

       本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!        相同线程是一并发框架模型,是一个单线程系统向外扩展成多个单线程的系统.这样的结果就是多个单线程并行运行. 为什么是单线程系统?         你也许会感到好奇,为什么当今还有人设计单线程系统.单线程系统之所以这么普及,是因为单线程系统相对于多线程并发系统更为简单.单线程系统不需要与其他线程共享任何数据.这就使得单线程系统可以使用非并发的数据结构,可以更

Java 并发/多线程教程(八)-竞态条件和临界区

      本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!       竞态条件是在临界区内可能发生的一种特殊情况.临界区是多线程并发执行一代码,根据线程的执行顺序可能产生多种结果的区域.多线程在临界区执行代码的结果可能不一样,不同的结果取决于线程的执行顺序.也就是说,临界区包含竞态条件.竞态一词源于隐喻,线程在临界区进进行资源竞争,在临界区的资源竞争影响最后的结果.      这听起来有点复杂,在下面的篇幅中,将会在下面的篇幅