java.lang.Thread

目录

一、什么是线程(Thread)与进程(Process)

         1.什么是进程

          2.什么是线程

          3.线程与进程的区别

 二、线程(Thread)

            1.线程的使用

            2.线程的五大状态

            3.线程创建的三种方法

                   1).继承Thread类,重写run方法

                      2).实现Runnable接口

                      3).创建FutureTask对象

             4.线程的api

                 1).构造器

                     2).常用api 

                    3).线程调度

                     3).守护线程

          5.线程安全问题(锁机制)

            1).临界资源与同步异步操作

                2).锁机制(Synchronized)

                 3).锁的一些api

                 3).经典问题,生产者消费者问题

           5.线程池及其api

                     1)什么是线程池

                      1)线程的api


 


一、什么是线程(Thread)与进程(Process)

         1.什么是进程

           狭义定义:进程是正在运行的程序的实例

           广义定义:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动,他是操作系统动态执行的基本单元,在传统的操作系统中,进程是基本的分配单元,也是基本的执行单元

概念:

            1.进程是一个实体,每一个进程都有它自己的地址空间,一般情况下,包括文本区、数据区域、和堆栈。文本区域存储处理器执行的代码。 数据区域存储变量和进程执行期间使用的动态分配的内存。 堆栈区存储的活动那个过程调用的指令和本地变量。

             2.进程是一个”执行中的程序“。程序是一个没有生命的实体,只有处理器赋予程序生命是(就是操作系统分配系统资源),他才能成为一个活动的实体,我们称其为进程

注:进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。

进程的概念主要有两点
              
          通俗点说,进程是操作系统中运行的一个任务  

          2.什么是线程

        线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

          1.进程拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问。即同一个进程中的多个线程共享一款内存空间和一组系统资源。 线程本身也有一个供程序执行时的堆栈,在线程切换时,负荷小,因此线程也被称为轻负荷进程。

           2.线程是进程中所包含的一个或多个执行单元。线程只能归属于一个进程,并且它只能访问该进程所拥有的资源。

           3.一个线程就是进程的一个顺序执行流。

           4.线程是程序中一个单一的顺序控制流程。进程内有一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指令运行时的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程

           通俗地说,线程是应用程序中的一个任务执行流。

          3.线程与进程的区别

     1.进程是操作系统运行的一个任务,线程是进程中运行的一个任务。

     2.进程是资源分配的最小单位(相互独立),线程是程序执行的最小单位(cpu调度的基本单元)。

     3.进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据 段,这种操作非常昂贵。 进程之间的通信需要以IPC进行。

     4.线程是轻量级的进程,同一个进程中可以包含多个线程。  多线程共享进程中的数据,使用相同的地址空间, 因此,线程之间的通信更方便,CPU切换(或创建)一个线程的开销远比进程要小很多。

      5.一个进程结束,其内的所有线程都结束,但不会对另外一个进程造成影响。多线程程序,一个线程结束,有可能会造成其他线程结束。

 二、线程(Thread)

            1.线程的使用

           当一个程序中需要“同时”完成多个任务的情况下,我们可以将每个任务定义成一个线程,使他们得以同时工作,有些时候,虽然可以使用单一线程完成,但是使用多线程可以更快完成。

注:并发原理

             多个线程“同时运行”只是我们感官上的一种表现。其实, 线程是并发运行的。操作系统将时间划分成很多时间片段,尽可能的均匀分配给每一个线程,获取时间片段的线程被CPU运行,而其他线程处于等待状态。所以这种微观上是走走停停,断断续续的,宏观上都在运行的现象叫并发。但不是绝对意义上的“同时发生”。

            2.线程的五大状态

    (1)新建状态(New):新创建了一个线程对象。
    (2)就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
    (3)运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
    (4)阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
                 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
                 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
                 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
       (5)死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

            3.线程创建的三种方法

                   1).继承Thread类,重写run方法

  创建该类对象,调用start方法开启线程。start方法可以将该线程对 象纳入可执行线程池中。切记,不是调用run方法

 /* 线程的创建方式:
 * 	方法一 既传承Thread类型,重写run方法
 *		 run方法的逻辑就是我们要定义的任务逻辑
 * 		启动线程要使用start方法而不是run方法
 *
 */
public class Threadtest { 
	 public static void main(String[] args) {
		Ms m1=new Ms();
		Ms1 n2=new Ms1();
		m1.start();
		n2.start();
	}

}
class Ms extends Thread{
       //打印100个你好
	public void run() {
		for(int i=0;i<=100;i++){
		System.out.println("nihao");
		}
	}
}
class Ms1 extends Thread{
     //打印1-100
	public void run() {
		for(int i=0;i<=100;i++){
		System.out.println(i);
		}
	}
}

                      2).实现Runnable接口

线程的创建方式2
 * 步骤一:实现Runnable接口 ,重写run方法
 * 步骤二:创建任务体对象,传入Thread,构建Thread实例
 * 步骤三:调用Thread的start方法

注:方法二优于方法一,将线程对象和线程任务对象分离开。降低了耦合性,利于维护实现Runnable接口比继承Thread类所具有的优势:  适合多个相同的程序代码的线程去处理同一个资源;  可以避免java中的单继承的限制;增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。


/**
 * 线程的创建方式2
 * 步骤一:实现Runnable接口 
 * 		重写run方法
 * 步骤二:创建任务体对象,传入Thread,构建Thread实例
 * 步骤三:调用Thread的start方法
 */
package testThread;

public class Threadtest { 
	 public static void main(String[] args) {
		Runnable m1=new Ms();
		Runnable n2=new Ms1();
		Thread t1 =new Thread(m1);
		Thread t2 =new Thread(n2);
		t1.start();
		t2.start();
	}

}
class Ms implements  Runnable {
	//打印100条nihao
	public void run() {
		for(int i=0;i<=100;i++){
			System.out.println("nihao");
			}
	}
}
class Ms1 implements  Runnable{
     //打印1-100
	public void run() {
		for(int i=0;i<=100;i++){
		System.out.println(i);
		}
	}
}

                      3).创建FutureTask对象

创建FutureTask对象,传入Callable子类对象
再将FutureTask对象 传入Thread对象
调用其start方法

/**
 * 线程的创建方式三:
 *  创建FutureTask对象,传入Callable子类对象
 *  再将FutureTask对象 传入Thread对象
 *  调用其start方法
 * 
 */
public class ThreadDemo03 {
	public static void main(String[] args) throws Exception {
		FutureTask<Integer> task = 
				new FutureTask<Integer>(
						new Callable<Integer>(){
							public Integer call() throws Exception {
								int sum=0;
								for(int i=1 ; i<=100;i++){
									sum+=i;
								}
								return sum;
							}
							
						});
				
			Thread t1=new Thread(task);
			t1.start();
			//FutureTask的get方法是获取Callable任务的返回值 而get方法是一个阻塞效果
			System.out.println(task.get().intValue());

	}
}

             4.线程的api

                 1).构造器

Thread()

分配一个新的 Thread对象。

Thread(Runnable target)

使用指定Runnable对象作为参数,创建一个Thread对象

Thread(Runnable target, String name)

使用指定Runnable对象作为参数,创建一个Thread对象,并指定对象名为name.

Thread(String name)

创建一个Thread对象,并指定名称为name

                     2).常用api 

booleanisAlive()

测试这个线程是否活着。

booleanisDaemon()

测试这个线程是否是守护线程。

booleanisInterrupted()

测试这个线程是否被中断。

voidjoin()

等待这个线程死亡。

voidjoin(long millis)

等待这个线程死亡最多 millis毫秒。

voidjoin(long millis, int nanos)

等待最多 millis毫秒加上 nanos纳秒这个线程死亡。

static voidyield()

对调度程序的一个暗示,即当前线程愿意产生当前使用的处理器。

longgetId()

返回此线程的标识符。

StringgetName()

返回此线程的名称。

intgetPriority()

返回此线程的优先级。

Thread.StategetState()

返回此线程的状态。

 

                    3).线程调度

 线程的切换是由线程调度控制的,我们无法通过代码来干涉,但是我们可以通过提高线程的优先级来最大程度的改善线程获取时间片段的概率。线程的优先级被划分为10级,值分别为1-10,其中1最低,10最高。线程提供了三个常量来表示最低,最高,以及默认优先级

static intMAX_PRIORITY

线程可以拥有的最大优先级。

static intMIN_PRIORITY

线程可以拥有的最小优先级。

static intNORM_PRIORITY

分配给线程的默认优先级。

       这里重点说一下sleep方法,yield方法和join方法 

static  void  sleep(long millis)

线程睡眠方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()方法平台移植性好。

   static  void  yield()
线程让步方法,暂停当前正在执行的线程对象,使之处于可运行状态,把执行机会让给相同或者更高优先级的线程。

/**
 * 线程优先级:
 * 		以为多个线程的切换,是由线程调度(cpu)来决定的
 * 		程序员无法干涉。但是可以通过线程的优先级来改善线程获取时间片段的改率
 * 		优先级分10级 分别是1-10 1最低 10 最高
 * 同事提供了三个常量来表示最低最高默认
 */
public class ThreadDemo05 {
	public static void main(String[] args) {
		Thread t1 =new Thread(
				new Runnable(){

					public void run() {
						for(int i=0;i<10;i++){
							/*让出时间片段*/
							Thread.yield();
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							System.out.println("hello word");
						}
						
					}});
		Thread t2=new Thread(){
			public void run() {
				for(int i=0;i<10;i++){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("hello word");
				}
			}
	
			};
		
		
		
		/*修改优先级不一定会让其优先完成 只是尽量让其优先度高*/
		t2.setPriority(10);
		t1.start();
		t2.start();

		System.out.println("优先级:"+t1.getPriority());
		System.out.println("优先级:"+t2.getPriority());
	
		/*方法:
		 * 	static void yield();
		 * 作用:使所在线程让出时间片段 进入就绪状态
		 * 注意:让出后 下一个时间片段可能被分配给此进程
		 * 
		 */
	

	
	
	}}

 void  join()
     线程加入方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运 行结束,当前线程再由阻塞转为就绪状态。

/**
 * join方法:
 * void join();
 * 	作用 :表示调用者加入到另外一个线程里,等调用者执行完另外一个线程才能进入就绪状态,
 * 		 当调用者正在运行时 另外一个线程处于阻塞状态。
 * 	
 * 案例:
 * 		完成电影的下载和播放
 * 		下载完成后 播放才开始
 * 
 * 匿名内部类可以直接访问外部类的变量但是必须适应final修饰
 * jdk1.8以后不需要使用
 */
public class ThreadDemo07 {
	public static void main(String[] args) {
		final Thread download=new Thread() {
			public void run(){
				for(int i=1;i<=100;i++){
					System.out.println("电影下载完成百分比"+i+"%");
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println("下载成功");
			}
		};
		Thread play =new Thread(){
			public void run(){

				try {
					download.join();
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				for(int i=1;i<=100;i++){
					System.out.println("电影观看完成百分比"+i+"%");
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println("观看完成");
			}
		};
		download.start();
		play.start();
	}
}

线程被打断方法
 void interrupt();
 当线程睡眠阻塞被打断会报异常 

/**
 * 线程被打断方法
 * void interrupt();
 *	当线程睡眠阻塞被打断会报异常
 *案例:
 *	黄宏砸墙吵醒林永健
 */
public class ThreadDemo08 {
	public  static void main(String[] args) {
		final Thread lin=new Thread(){
			public void run(){
				try {
					Thread.sleep(8000);
					System.out.println("林说:真香,好舒坦");
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.out.println("林问:干嘛呢!干嘛呢!");
				}
				
			}
		};
		Thread huang=new Thread(){
			public void run(){
				for(int i=0;i<10;i++){
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("黄说:80!");
				}
				System.out.println("咣当一声!墙透了");
				System.out.println("黄说,搞定 800到手");
				//此时吵醒了林
				lin.interrupt();
			}
		};

		huang.start();
		lin.start();
		
	}
}

 

                     3).守护线程

守护线程与普通线程在表现上没有什么区别,我们只需要通过Thread提供的方法来设定即可:
    void  setDaemon(boolean on)
当参数为true时该线程为守护线程。守护线程的特点是,当进程中只剩下守护线程时,所有守护线程强制终止。GC就是运行在一个守护线程上的

/*
*Rose要跳海,每0.5秒喊一次"I'll jump"。Jack来守护她,Rose每喊一次他就喊一次"You jump,I *jump"。Rose跳海了之后Jack也跟着跳了。
*/
public class ThreadDemo06 {
	public static void main(String[] args) {
		Thread rose=new Thread(){
			public void run(){
				for(int i=0;i<10;i++){
					System.out.println("rose:我要跳海");
							try {
								Thread.sleep(500);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
				}
				System.out.println("噗通!!!!!!!!!!!!!");
				System.out.println("rose卒!!!!!!!!!!!!!!!!!!!");
			}
	};
	Thread jack = new Thread() {
		public void run (){
			while(true){
				System.out.println("jack:你跳我就跳");
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	};
	/*
	 * 将jack设置成守护线程
	 * setDaemon(boolean f)
	 * true表示为守护线程
	 * false表示为普通线程
	 */
	jack.setDaemon(true);
	rose.start();
	jack.start();
	
	
}
}

          5.线程安全问题(锁机制)

            1).临界资源与同步异步操作

 当多个线程并发读写同一个临界资源时,会发生“线程并发安全问题”。

临界资源:实例变量;静态公共变量。

        异步操作:多线程并发的操作,相当于各干各的 
        同步操作:有先后顺序的操作,相当于你干完我再干

如果想解决线程安全问题,需要将异步的操作变为同步操作。

                2).锁机制(Synchronized)

    Java提供了一种内置的锁机制来支持原子性(不可分割性),通过关键字synchronized来进行同步代码块。同步代码块包
含两部分:充当锁的对象;由这个锁保护的代码块。
       线程进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁,无论是通过正常途径退出还是通过抛出异常退出都一样。获取内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。在使用同步块时,应该尽量在允许的情况下减少同步范围。

1.    合适的锁对象

使用关键字synchronized同步方法内的部分代码块时,对于充当锁的对象,应该注意:多个需要同步的线程在访问该同步块时,看到的应该是同一个锁的对象引用,否则不同步。通常我们会使用this来作为锁对象

2.    合适的锁范围

在使用同步块时,应该尽量在允许的情况下减少同步范围,来提高并发的执行效率

Synchronized关键字的作用域

1.同步方法内的部分代码块,或者全部代码块(相当于给方法直接加锁):通常情况下锁对象都是this。

2.同步静态方法:该方法的锁对象是类对象。因为每个类都有唯一的一个类对象。获取类对象的方法为:类名.class。

 注:    静态方法与非静态方法同时声明了synchronized,他们之间是非互斥关系的。因为静态方法的锁是类对象,而非静态方法的锁对象是当前方法所属的对象。
 

 

/**
 * 案例:安全隐患问题
 * 	桌子上有二十个苹果 有两个人分别取拿这些苹果
 * 	一个一个的拿
 */
public class ThreadDemo09 {
	public static void main(String[] args) {
		Person p1=new Person();
		Person p2=new Person();
		p1.start();
		p2.start();
	}
}
class Person extends Thread{
	static int num = 5;//模拟桌子上的二十个苹果
	static Object obj=new Object();
	public void run(){
		//从桌子上取苹果
		while(num!=0){
			Thread.yield();   
			Thread c= Thread.currentThread();
			System.out.println(c.getName()+"取走一个,剩余"+getApple()+"个");
		}
	}
	public int getApple(){
		//小括号里需要有一个共同的锁对象
		//obj因为是静态成员变量 只有一份 任何person看到的都是obj
		//因此可以作为锁对象
		//因为控制台输出为流写出 但是不同线程使用的流不同 所以写出的时间可能有差别 所以会出现乱序状况
		synchronized (obj) {
			
			if(num!=0){
				num--;	
			}
	
		}
		return num;
	
	}
}

                 3).锁的一些api

1.void  wait()  : 表示持有对象锁的线程A准备释放对象锁权限,释放cpu资源并进入等待。

2.void  notify()  : 表示持有对象锁的线程A准备释放对象锁权限,通知jvm唤醒某一个竞争该对象锁的线程。

3.void  notifyAll()  : Object类中的方法,表示持有对象锁的线程A准备释放对象锁权限,通知jvm唤醒所有竞争该对象锁的线程。                                     所有被唤醒的线程不再等待,进入可执行状态。
! 

                 3).经典问题,生产者消费者问题

package com.hyxy.Thread;
/**
 * 经典案例:生产者消费者案例
 * 
 *
 */
public class ProductCostumeDemo {
	public static void main(String[] args) {
		Epot epot=new Epot(50);
		Costumer c1=new Costumer(20,"消费者1",epot);
		Costumer c2=new Costumer(40,"消费者2",epot);
		Costumer c3=new Costumer(50,"消费者3",epot);
		Productor p1=new Productor(epot,30,"生产者1");
		Productor p2=new Productor(epot,60,"生产者2");
		Productor p3=new Productor(epot,50,"生产者3");
		c1.start();
		c2.start();
		c3.start();
		p1.start();
		p2.start();
		p3.start();
	}
	

}
/**
 * 消费者
 * */
class  Costumer extends Thread{
	private int needNum;
	private Epot epot;
	public int getNeedNum() {
		return needNum;
	}

	public void setNeedNum(int needNum) {
		this.needNum = needNum;
	}

	public String getNickname() {
		return nickname;
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}

	private String nickname;
	
	public Epot getEpot() {
		return epot;
	}

	public void setEpot(Epot epot) {
		this.epot = epot;
	}

	public Costumer(int needNum, String name,Epot epot) {
		//将name赋值给Thraed属性name
		setName(name);
		this.needNum = needNum;
		this.nickname = name;
		this.epot=epot;
	}
	
	
	/*任务体*/
	public void run(){
		System.out.println(nickname+"准备买-------");
		epot.costume(needNum);
		System.out.println(nickname+"买完后--潇洒的一转身");
	}
	
}

class Productor extends Thread{
	private Epot epot;
	private int Pronum;
	private String nickname ;
	public Epot getEpot() {
		return epot;
	}
	public void setEpot(Epot epot) {
		this.epot = epot;
	}
	public int getPronum() {
		return Pronum;
	}
	public void setPronum(int pronum) {
		Pronum = pronum;
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	public Productor(Epot epot, int pronum, String nickname) {
		setName(nickname);
		this.epot = epot;
		Pronum = pronum;
		this.nickname = nickname;
	}
	public void run(){
		System.out.println(nickname+"要开始生产啦-------------------");
		epot.production(Pronum);
		System.out.println(nickname+"生产完了 ,疲惫的走了++++++++++");
	}
}





/**
 * 仓库类型
 * */
class Epot{
	/*
	 * 属性  当前容量
	 */
	private static final int MAX_NUM=100;
	/*
	 * 属性 初始值
	 */
	private int num;
	/*
	 * 构造器
	 */
	public  Epot(int num){
		this.num=num;
	}
	/*
	 * 存储生产者生产的数据
	 */
	public synchronized void production(int proNum){
		while(proNum+num>MAX_NUM){
			try {
				/*此时,此线程 拥有锁 准备释放锁 进入等待状态*/
				this.wait();
				/*此时,等待被唤醒,准备进入就绪状态 因此 是一个循环判断是否满足条件*/
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		String name = Thread.currentThread().getName();
		//循环结束:表示此线程可以生产并储存
		System.out.println(name+"开始生产 ,仓库数量为num"+num+"生产数量为:"+proNum);
		num+=proNum;
		System.out.println(name+"生产结束,生产后的仓库数量为:"+num);
		//任务结束:通知唤醒其他等待阻塞状态下的线程
		this.notifyAll();
	}
	public synchronized void costume(int needNum){
		while(needNum>num){
			try {
				/*此时,此线程 拥有锁 准备释放锁 进入等待状态*/
				this.wait();
				/*此时,等待被唤醒,准备进入就绪状态 因此 是一个循环判断是否满足条件*/
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		String name = Thread.currentThread().getName();
		//循环结束:表示此线程可以生产并储存
		System.out.println(name+"开始消费 ,仓库数量为num"+num+"消费数量为:"+needNum);
		num-=needNum;
		System.out.println(name+"消费结束,生产后的仓库数量为:"+num);
		//任务结束:通知唤醒其他等待阻塞状态下的线程
		this.notifyAll();
	}
}

           5.线程池及其api

                     1)什么是线程池

    1.减少线程对象的创建,减小内存开销
    2.方便管理线程
   原理:就是一些线程的集合,线程的状态不是死亡状态 当线程池接受外面的任务是 线程池的管理器会查看是否有空闲线程
如果有就会将任务分配给它 如果没有任务就处于等待队列中

                      1)线程的api

方法1:newSingleThreadExecutor()    获取单个线程的线程池对象,内部维护了一个无界队列用于存储任务

             如果向SingleThreadExecutor提交多个任务,这些任务将排队。比如有5个Task:abcde;执行顺序为abced

方法2: newFixedThreadPool(int nThreads)    创建一个固定数量线程的线程池,维护一个为无界队列

   、      newSingleThreadExecutor() 相当于 newFixedThreadPool(1)

           比如newFixedThreadPool(2),t1和t2先执行,执行顺序不一定,然后t3,t4,t5随机两个执行,顺序也不一定。

方法三:   newCachedThreadPool()
           创建一个可以根据需求来创建新线程的线程池对象,如果有冲用的 ,会优先使用 添加新任务时 如果有空闲的就使用该线程 如果没有 那么就新建一个线程

方法4:newScheduledThreadPool(int corePoolSize)   创建一个线程池,可以进行设置延迟或者是定时来执行任务。此方法的返回值类型为   ScheduledExecutorService
 

public class ThreadPoolDemo01 {
	public static void main(String[] args) {
		/*Executers例提供的静态方法
		 * 方法1:
		 * 使用newSingleThreadExecuter();
		 * 创建一个具有单一线程对象的线程池
		 * 
		 */
		//ExecutorService pool=Executors.newSingleThreadExecutor();
		
		/*
		 * 方法二:
		 * 	newFixedThreadPool(int nThreads)
		 * 创建一个固定数量的线程池
		 * 内部维护了一个无界数列
		 * */
		ExecutorService pool =Executors.newFixedThreadPool(2);
		
		
		//创建五个任务体
		Task t1=new Task("a");
		Task t2=new Task("b");
		Task t3=new Task("c");
		Task t4=new Task("d");
		Task t5=new Task("e");
		/*
		 * 将五个任务添加到线程池里
		 * execute(Runnable r)
		 * 添加任务方法,线程的启动有由线程池来管理。无需程序员操作
		 */
		pool.execute(t1);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t4);
		pool.execute(t5);
		
		
		/*
		 * 线程池不用的情况下请关闭
		 * shutdown();
		 */
		pool.shutdown();
	}
}
class Task implements Runnable{
	//锁对象
	static Object obj=new Object();
	private String name;
	public Task(String name){
		this.name=name;
	}
	public  void run() {
		/*随机生成一个100以内的整数 打印10次*/
		synchronized (obj) {
			int num=(int)(Math.random()*100);
			for(int i=0;i<10;i++){
				System.out.println(name+"第"+i+"次"+num);
		}
		}
	}
	
}
public class ThreadPoolDemo02 {
	public static void main(String[] args) {
		ExecutorService pool=Executors.newCachedThreadPool();
		Task01 t1=new Task01();
		Task01 t2=new Task01();
		Task01 t3=new Task01();
		Task01 t4=new Task01();
		Task01 t5=new Task01();
		Task01 t6=new Task01();
		pool.execute(t1);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t4);
		pool.execute(t5);
		/*使main线程睡眠一秒后再添加第六个任务
		 * 那么第六个任务就会重用之前创建的某一个空闲线程
		 * */
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		pool.execute(t6);
		
		
		pool.shutdown();
	}
}
class Task01 implements Runnable{
	public void run() {
		int num=(int)(Math.random()*100);
		String name=Thread.currentThread().getName();
		for(int i=0;i<10;i++){
				System.out.println(name+"第"+i+"次"+num);
		}
	}
	
}

 

public class ThreadPoolDemo03 {
	public static void main(String[] args) {
		/*方法四:
		 * ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
		 *	创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。  
		 *此时 此方法的返回值类型为ScheduleanExecutorService
		 */
		ScheduledExecutorService pool=
				Executors.newScheduledThreadPool(3);
		Task01 t1=new Task01();
		Task01 t2=new Task01();
		Task01 t3=new Task01();
		Task01 t4=new Task01();
		Task01 t5=new Task01();
		/*
		 *schedule(command,delay,unit) 
		 *command:任务体对象
		 *delay:延迟时间
		 *unit: 时间单位
		 */
		pool.schedule(t1,5,TimeUnit.SECONDS);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t4);
		pool.execute(t5);
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值