Java线程----概念,创建

 

一.概念(定义)

1 . 进程 :是操作系统中运行的一个任务。进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

2 . 线程 :是进程的一个顺序执行流。线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

  • 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
  • 并行与并发:
    • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
    • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

二. 进程与线程的区别

  进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

2) 线程的划分尺度小于进程,使得多线程程序的并发性高。

3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

6).优缺点

线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

三 . Java线程的创建及启动

1)继承Thread类(重写run方法来定义线程要执行的任务代码)

 1 public class ThreadDemo1 {
 2     public static void main(String[] args) {
 3         Thread t1 = new MyThread1();
 4         Thread t2 = new MyThread2();
 5         /*
 6          * 启动线程要调用start方法,不要直接调用
 7          * run方法。
 8          * 当线程启动后,被分配时间片开始运行时会
 9          * 自动调用run方法。
10          */
11         t1.start();
12         t2.start();
13     }
14 }
15 /**
16  * 第一种创建线程存在两个不足:
17  * 1:由于java是单继承,所以导致继承了Thread不能
18  *   在继承其他类,在实际开发中经常会出现继承冲突
19  *   问题
20  * 2:由于重写线程run方法,将线程要执行的任务定义
21  *   在了线程中,导致任务与线程有一个耦合关系,
22  *   不利于线程重用。  
23  * @author adminitartor
24  *
25  */
26 class MyThread1 extends Thread{
27     public void run(){
28         for(int i=0;i<1000;i++){
29             System.out.println("你是谁啊?");
30         }
31     }
32 }
33 class MyThread2 extends Thread{
34     public void run(){
35         for(int i=0;i<1000;i++){
36             System.out.println("我是查水表的!");
37         }
38     }
39 }

 

2)实现Runnable接口(单独定义任务)

 1 /**
 2  * 第二种创建线程的方式
 3  * 实现Runnable接口单独定义任务
 4  * @author adminitartor
 5  *
 6  */
 7 public class ThreadDemo2 {
 8     public static void main(String[] args) {
 9         Runnable r1 = new MyRunnable1();
10         Runnable r2 = new MyRunnable2();
11         
12         Thread t1 = new Thread(r1);
13         Thread t2 = new Thread(r2);
14         
15         t1.start();
16         t2.start();
17     }
18 }
19 class MyRunnable1 implements Runnable{
20     public void run(){
21         for(int i=0;i<1000;i++){
22             System.out.println("你是谁啊?");
23         }
24     }
25 }
26 class MyRunnable2 implements Runnable{
27     public void run(){
28         for(int i=0;i<1000;i++){
29             System.out.println("我是查水表的!");
30         }
31     }
32 }

匿名内部类创建线程

 1 /**
 2  * 用匿名内部类形式完成线程两种方式的创建
 3  * @author adminitartor
 4  *
 5  */
 6 public class ThreadDemo3 {
 7     public static void main(String[] args) {
 8         //方式一
 9         Thread t1 = new Thread(){
10             public void run(){
11                 for(int i=0;i<1000;i++){
12                     System.out.println("你是谁啊?");
13                 }
14             }
15         };
16         
17         //方式二
18         Runnable runn = new Runnable(){
19             public void run(){
20                 for(int i=0;i<1000;i++){
21                     System.out.println("我是查水表的!");
22                 }
23             }
24         };
25         Thread t2 = new Thread(runn);
26         
27         t1.start();
28         t2.start();
29         
30     }
31 }

 

3)线程池

Java5的线程池分好多种:固定尺寸的线程池、可变尺寸连接池。

 

在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供大量创建连接池的静态方法,是必须掌握的。
一、固定大小的线程 1 import java.util.concurrent.Executors; 
 2 import java.util.concurrent.ExecutorService; 
 3 
 4 /** 
 5 * Java线程:线程池- 
 6 * 
 7 * @author 8 */ 
 9 public class Test { 
10         public static void main(String[] args) { 
11                 //创建一个可重用固定线程数的线程池 
12                 ExecutorService pool = Executors.newFixedThreadPool(2); 
13                 //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 
14                 Thread t1 = new MyThread(); 
15                 Thread t2 = new MyThread(); 
16                 Thread t3 = new MyThread(); 
17                 Thread t4 = new MyThread(); 
18                 Thread t5 = new MyThread(); 
19                 //将线程放入池中进行执行 
20                 pool.execute(t1); 
21                 pool.execute(t2); 
22                 pool.execute(t3); 
23                 pool.execute(t4); 
24                 pool.execute(t5); 
25                 //关闭线程池 
26                 pool.shutdown(); 
27         } 
28 } 
29 
30 class MyThread extends Thread{ 
31         @Override 
32         public void run() { 
33                 System.out.println(Thread.currentThread().getName()+"正在执行。。。"); 
34         } 
35 }

输出结果为:

pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-2正在执行。。。 

Process finished with exit code 0

二、单任务线程池
 
在上例的基础上改一行创建pool对象的代码为:
                //创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 
                ExecutorService pool = Executors.newSingleThreadExecutor(); 
 
输出结果为:
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 

Process finished with exit code 0
 
对于以上两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。
一旦池中有线程完毕,则排队等待的某个线程会入池执行。
 
三、可变尺寸的线程池
 
与上面的类似,只是改动下pool的创建方式:
                //创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。 
                ExecutorService pool = Executors.newCachedThreadPool(); 
 
pool-1-thread-5正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-4正在执行。。。 
pool-1-thread-3正在执行。。。 
pool-1-thread-2正在执行。。。 

Process finished with exit code 0
 
四、延迟连接池
 1 import java.util.concurrent.Executors; 
 2 import java.util.concurrent.ScheduledExecutorService; 
 3 import java.util.concurrent.TimeUnit; 
 4 
 5 /** 
 6 * Java线程:线程池- 
 7 * 
 8 * @author Administrator 2009-11-4 23:30:44 
 9 */ 
10 public class Test { 
11         public static void main(String[] args) { 
12                 //创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 
13                 ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); 
14                 //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 
15                 Thread t1 = new MyThread(); 
16                 Thread t2 = new MyThread(); 
17                 Thread t3 = new MyThread(); 
18                 Thread t4 = new MyThread(); 
19                 Thread t5 = new MyThread(); 
20                 //将线程放入池中进行执行 
21                 pool.execute(t1); 
22                 pool.execute(t2); 
23                 pool.execute(t3); 
24                 //使用延迟执行风格的方法 
25                 pool.schedule(t4, 10, TimeUnit.MILLISECONDS); 
26                 pool.schedule(t5, 10, TimeUnit.MILLISECONDS); 
27                 //关闭线程池 
28                 pool.shutdown(); 
29         } 
30 } 
31 
32 class MyThread extends Thread { 
33         @Override 
34         public void run() { 
35                 System.out.println(Thread.currentThread().getName() + "正在执行。。。"); 
36         } 
37 }

pool-1-thread-1正在执行。。。 
pool-1-thread-2正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-2正在执行。。。 

Process finished with exit code

五、单任务延迟连接池
 
在四代码基础上,做改动
                //创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 
                ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-1正在执行。。。 

Process finished with exit code 0 
 
六、自定义线程池
 1 import java.util.concurrent.ArrayBlockingQueue; 
 2 import java.util.concurrent.BlockingQueue; 
 3 import java.util.concurrent.ThreadPoolExecutor; 
 4 import java.util.concurrent.TimeUnit; 
 5 
 6 /** 
 7 * Java线程:线程池-自定义线程池 
 8 * 
 9 * @author Administrator  
10 */ 
11 public class Test { 
12         public static void main(String[] args) { 
13                 //创建等待队列 
14                 BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20); 
15                 //创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 
16                 ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bqueue); 
17                 //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 
18                 Thread t1 = new MyThread(); 
19                 Thread t2 = new MyThread(); 
20                 Thread t3 = new MyThread(); 
21                 Thread t4 = new MyThread(); 
22                 Thread t5 = new MyThread(); 
23                 Thread t6 = new MyThread(); 
24                 Thread t7 = new MyThread(); 
25                 //将线程放入池中进行执行 
26                 pool.execute(t1); 
27                 pool.execute(t2); 
28                 pool.execute(t3); 
29                 pool.execute(t4); 
30                 pool.execute(t5); 
31                 pool.execute(t6); 
32                 pool.execute(t7); 
33                 //关闭线程池 
34                 pool.shutdown(); 
35         } 
36 } 
37 
38 class MyThread extends Thread { 
39         @Override 
40         public void run() { 
41                 System.out.println(Thread.currentThread().getName() + "正在执行。。。"); 
42                 try { 
43                         Thread.sleep(100L); 
44                 } catch (InterruptedException e) { 
45                         e.printStackTrace(); 
46                 } 
47         } 
48 }

pool-1-thread-1正在执行。。。 
pool-1-thread-2正在执行。。。 
pool-1-thread-2正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-2正在执行。。。 
pool-1-thread-1正在执行。。。 
pool-1-thread-2正在执行。。。 

Process finished with exit code 0

创建自定义线程池的构造方法很多,本例中参数的含义如下:

ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue)
用给定的初始参数和默认的线程工厂及处理程序创建新的 ThreadPoolExecutor。使用 Executors 工厂方法之一比使用此通用构造方法方便得多。
参数:
corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
抛出:
IllegalArgumentException - 如果 corePoolSize 或 keepAliveTime 小于零,或者 maximumPoolSize 小于或等于零,或者 corePoolSize 大于 maximumPoolSize。
NullPointerException - 如果 workQueue 为 null

 

posted @ 2017-04-13 03:04  等你,在雨中  阅读(122)  评论(0)    收藏  举报