并发--基本的线程机制

1. 基本概念

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System VSunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符信号处理等等。但同一进程中的多个线程有各自的调用栈call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。

一个进程可以有很多线程,每条线程并行执行不同的任务。

在多核或多 CPU,或支持Hyper-threadingCPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。(摘自百度百科)

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

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

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

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

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

2 定义任务

线程可以驱动任务,因此需要一种描述任务的方式。创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。

2.1 重写Thread类的的run方法

public class Thread extends Object implements Runnable

查看 API文档可知:其实 Thread 也是实现 Runable 接口的类

 1 package thread;
 2 
 3 public class liftOff implements Runnable {
 4     protected int countDown=10;
 5     private static int taskCount=0;
 6     private final int id=taskCount++;
 7     public liftOff() {}
 8     public liftOff(int countDown) {
 9         this.countDown=countDown;
10     }
11     public String status() {
12         return "#"+id+"("+(countDown>0?countDown:"liftOff")+"),";
13     }
14     @Override
15     public void run() {
16         // TODO Auto-generated method stub
17         while(countDown-->0) {
18             System.out.print(status());
19             Thread.yield();
20         }
21     }
22 
23 }
package thread;

public class basicThread {
    public static void main(String[] args){
        Thread t=new Thread(new liftOff());
        t.start();
        System.out.println("Waiting for liftOFF");
    }
}//Output
/*#0(9),#0(8),#0(7),#0(6),#0(5),#0(4),#0(3),#0(2),#0(1),#0(liftOff),#1(9),#1(8),#1(7),#1(6),#1(5),#1(4),#1(3),#1(2),#1(1),#1(liftOff),#2(9),#2(8),#2(7),#2(6),#2(5),#2(4),#2(3),#2(2),#2(1),#2(liftOff),#3(9),#3(8),#3(7),#3(6),#3(5),#3(4),#3(3),#3(2),#3(1),#3(liftOff),#4(9),#4(8),#4(7),#4(6),#4(5),#4(4),#4(3),#4(2),#4(1),#4(liftOff),

*/
View Code

2.2 声明实现 Runnable 接口

 1 package thread;
 2 
 3 public class mainThread {
 4     public static void main(String[] args) {
 5         liftOff launch=new liftOff();
 6         launch.run();
 7     }
 8 }
 9 /* Output   #0(9),#0(8),#0(7),#0(6),#0(5),#0(4),#0(3),#0(2),#0(1),#0(liftOff),
10 */

从运行结果可以看出,并发是每个线程是互不影响的。

异步时,new Thread的弊端如下:

a. 每new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
相比new ThreadJava提供的四种线程池的好处在于:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。

2.3 使用 Executor接口

 执行已提交的 Runnable 任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。通常使用 Executor 而不是显式地创建线程。

不过,Executor 接口并没有严格地要求执行是异步的。在最简单的情况下,执行程序可以在调用者的线程中立即运行已提交的任务: 更常见的是,任务是在某个不是调用者线程的线程中执行的。以下执行程序将为每个任务生成一个新线程。

许多 Executor 实现都对调度任务的方式和时间强加了某种限制。以下执行程序使任务提交与第二个执行程序保持连续,这说明了一个复合执行程序。

此包中提供的 Executor 实现实现了 ExecutorService,这是一个使用更广泛的接口。ThreadPoolExecutor 类提供一个可扩展的线程池实现。Executors 类为这些 Executor 提供了便捷的工厂方法。

内存一致性效果:线程中将 Runnable 对象提交到 Executor 之前的操作 happen-before 其执行开始(可能在另一个线程中)。

Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

 

 1)使用CachedThreadPool

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

 1 package thread;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 public class cachedThreadPool {
 7     public static void main(String[] args) {
 8         ExecutorService exec = Executors.newCachedThreadPool();
 9         for (int i = 0; i < 5; i++) {
10             exec.execute(new liftOff());
11         }
12         exec.shutdown();
13 
14     }
15 }/*Output #1(9),#0(9),#1(8),#0(8),#3(9),#4(9),#2(9),#0(7),#2(8),
#3(8),#0(6),#1(7),#0(5),#3(7),#0(4),#2(7),#4(8),#1(6),#3(6),#2(6),#4(7),#1(5),#3(5),
#1(4),#2(5),#0(3),#4(6),#3(4),#1(3),#2(4),#0(2),#4(5),#1(2),#2(3),#1(1),#3(3),#2(2),#4(4),
#0(1),#1(liftOff),#2(1),#0(liftOff),#3(2),#2(liftOff),#4(3),#3(1),#4(2),#3(liftOff),#4(1),#4(liftOff),
16 */

 

  2)使用FixedThreadPool

  创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

 1 package thread;
 2 
 3 
 4 
 5 import java.util.concurrent.ExecutorService;
 6 import java.util.concurrent.Executors;
 7 
 8 public class fixedThreadPool {
 9     public static void main(String[] args) {
10         ExecutorService exec = Executors.newFixedThreadPool(5);
11         for (int i = 0; i < 5; i++) {
12             exec.execute(new liftOff());
13         }
14         exec.shutdown();
15 
16     }
17 }
18 /*Output #1(9),#0(9),#1(8),#0(8),#3(9),#4(9),
#2(9),#0(7),#2(8),#3(8),#0(6),#1(7),#0(5),#3(7),#0(4),#2(7),
#4(8),#1(6),#3(6),#2(6),#4(7),#1(5),#3(5),#1(4),#2(5),#0(3),#4(6),
#3(4),#1(3),#2(4),#0(2),#4(5),#1(2),#2(3),#1(1),#3(3),#2(2),#4(4),#0(1),#1(liftOff),
#2(1),#0(liftOff),#3(2),#2(liftOff),#4(3),#3(1),#4(2),#3(liftOff),#4(1),#4(liftOff),
19 20 * */

  3)使用SingleThreadPool

  创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:


package thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class singleThreadPool {
public static void main(String[] args) {
ExecutorService exec = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
exec.execute(new liftOff());
}
exec.shutdown();


}
}/*#0(9),#0(8),#0(7),#0(6),#0(5),#0(4),#0(3),#0(2),#0(1),#0(liftOff),
#1(9),#1(8),#1(7),#1(6),#1(5),#1(4),#1(3),#1(2),#1(1),#1(liftOff),
#2(9),#2(8),#2(7),#2(6),#2(5),#2(4),#2(3),#2(2),#2(1),#2(liftOff),
#3(9),#3(8),#3(7),#3(6),#3(5),#3(4),#3(3),#3(2),#3(1),#3(liftOff),
#4(9),#4(8),#4(7),#4(6),#4(5),#4(4),#4(3),#4(2),#4(1),#4(liftOff),
*/

 

  

原文地址:https://www.cnblogs.com/tianliang94/p/10633797.html