Java多线程

avatar
作者
猴君
阅读量:0

文章目录

多线程的创建

方式1:继承Thread类的方式进行实现

package day30_多线程;  public class Demo01 { 	// 方式1:继承Thread类的方式进行实现 	// 步骤1:继承Thread类 	// 步骤2:重写run方法 	// 步骤3:创建MyThread的对象,调用start方法启动线程 	public static void main(String[] args) { 		MyThread t1 = new MyThread(); 		t1.setName("线程1");// 给线程设置名字 		// 开启线程--此处需要注意:不能直接调用run方法,否则就是对象的创建和方法的调用 		t1.start(); 		t1.run(); 		for (int i = 0; i <= 50; i++) { 			System.out.println("main" + i); 		} 	} } 
package day30_多线程;  public class MyThread extends Thread { 	// 重写run方法,线程要执行的代码 	@Override 	public void run() { 		for (int i = 0; i <= 50; i++) { //			setName("测试"); 			System.out.println(getName() + ":" + i); 		} 	} } 

方式2:实现Runnable接口的方式进行实现

package day30_多线程;  public class Demo02 { 	// 方式2:实现Runnable接口的方式进行实现 	// 1.自定义一个类实现Runnable接口 	// 2.重写run方法 	// 3.创建自定义类的对象,将其作为参数 	// 4.创建一个Thread对象,参数为3,并开启线程 	public static void main(String[] args) { 		// 创建MyRunable的对象,表示多线程要执行的任务 		MyRunable r1 = new MyRunable();  		// 创建线程对象 		Thread t1 = new Thread(r1); 		Thread t2 = new Thread(r1); 		t1.setName("子线程1"); 		t2.setName("子线程2"); 		t1.start();// 开启线程 		t2.start();  		// 设置主线程的名字 		Thread mainThread = Thread.currentThread(); 		mainThread.setName("main主线程"); 		for (int i = 0; i <= 50; i++) { 			System.out.println(mainThread.getName() + ":" + i); 		} 	} } 
package day30_多线程;  public class MyRunable implements Runnable { 	@Override 	public void run() { 		for (int i = 0; i <= 50; i++) { 			// getName()为Thread类的方法,不能直接使用getName()方法 			// MyRunable和Thread类没有继承关系 			// 通过Thread的静态方法获取当前线程对象后获取方法名字 			Thread t1 = Thread.currentThread(); 			System.out.println(t1.getName() + ":" + i); 		} 	} } 

方式3:实现Callable接口的方式进行实现线程

package day30_多线程;  import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;  public class Demo03 { 	public static void main(String[] args) throws InterruptedException, ExecutionException { 		// 方式3:实现Callable接口的方式进行实现线程---和方式2相同 		// 特点:可以获取到多线程的运行结果 		// 步骤1:创建一个实现类来实现Callable接口 		// 步骤2:重写ca11方法(有返回值,表示多线程执行的任务的返回值) 		// 步骤3:创建实现类对象 		// 步骤4:创建FutureTask类型的对象(管理多线程执行后的结果) 		// 步骤5:Thread类的对象的创建,并启动  		// 创建Callable实现类对象(表示多线程要执行的任务) 		MyCallable m1 = new MyCallable(); 		// 创建FutureTask对象(作用管理多线程的运行结果) 		FutureTask<Integer> ft = new FutureTask<Integer>(m1); 		// 创建线程对象 		Thread t1 = new Thread(ft); 		// 启动线程 		t1.start();  		// 获取多线程运行的结果 		Integer num = ft.get(); 		System.out.println(num); 	} } 
package day30_多线程;  import java.util.concurrent.Callable;  public class MyCallable implements Callable<Integer> { 	//线程要执行的代码 	@Override 	public Integer call() throws Exception { 		int sum = 0; 		for (int i = 0; i <= 100; i++) { 			sum += i; 		} 		return sum; 	} } 

多线程的方法

**getName()😗*获取此线程名字
细节:如果没有给线程设置名字.线程也会有默认名称
格式:Thread-X(X的序号从0开始)

**void setName(String name)**设置线程的名字,构造方法进行设置线程名称

**Thread.currentThread();**获取当前的线程

**Thread.sleep(XXX);**让指定的线程休眠多少毫秒
细节:哪条线程执行到此方法,那么哪条线程就会在这里停留对应的时间
参数为毫秒 1秒=1000毫秒
当时间到了以后,线程会自动的醒来,继续执行下面的代码

getPriority() 获取优先级

setPriority() 设置优先级,范围1~10,默认优先级为5

数字越大优先级越高,但不是一定先执行完

**setDaemon(true)**设置守护线程

Thread.yield()

让出当前的cpu的执行权,让结果更加均匀一点,也不是绝对均匀。

当前的线程让出执行权后,再次进行抢夺资源也可能会抢到。

join()线程插队

守护线程setDaemon(true)将t2线程标记为守护线程

package day30_多线程方法;  //守护线程 public class Demo03 { 	public static void main(String[] args) { 		MyThread1 t1 = new MyThread1(); 		MyThread2 t2 = new MyThread2(); 		t1.setName("女神线程"); 		t2.setName("(备胎)守护线程"); 		// 在调用start()方法前, 		// 调用setDaemon(true)将t2线程标记为守护线程 		t2.setDaemon(true); 		t1.start(); 		t2.start(); 	} }  class MyThread1 extends Thread { 	@Override 	public void run() { 		for (int i = 0; i <= 10; i++) { 			System.out.println(getName() + "@" + i); 		} 	} }  class MyThread2 extends Thread { 	@Override 	public void run() { 		for (char c = 'A'; c <= 'Z'; c++) { 			System.out.println(getName() + "@" + c); 		} 	} } 

Thread.yield();

package day30_多线程方法;  public class Demo04 { 	public static void main(String[] args) { 		MyThread3 t1 = new MyThread3("线程1"); 		MyThread3 t2 = new MyThread3("线程2");  		t1.start(); 		t2.start(); 	} }  class MyThread3 extends Thread { 	public MyThread3(String string) { 		super(string); 	}  	@Override 	public void run() { 		for (int i = 0; i <= 100; i++) { 			System.out.println(getName() + "@" + i); 			// 让出当前的cpu的执行权,让结果更加均匀一点,也不是绝对均匀 			// 当前的线程让出执行权后,再次进行抢夺资源也可能会抢到 			Thread.yield(); 		} 	} } 

内部类创建线程

package day30_多线程方法;   public class Demo05 { 	public static void main(String[] args) { 		// 内部类创建线程 		Thread t1 = new Thread() { 			public void run() { 				for (char i = 'a'; i < 'z'; i++) { 					System.out.println(getName() + "@" + i); 					Thread.yield(); 				} 			} 		}; 		Thread t2 = new Thread() { 			public void run() { 				for (char i = 65; i < 'z'; i++) { 					System.out.println(getName() + "@" + i); 					Thread.yield(); 				} 			} 		}; 		t1.start(); 		t2.start(); 	} }  

t1.join()线程插队

package day30_多线程方法;  //join方法 public class Demo06 { 	public static void main(String[] args) throws InterruptedException { 		// 如果想要先执行线程1,再执行main方法,使用join,插队 		MyThread4 t1 = new MyThread4(); 		t1.setName("线程"); 		t1.start();  		// 将线程t1添加到当前线程的前面执行 		t1.join(); 		for (int i = 0; i < 100; i++) { 			System.out.println("main@" + i); 		} 	} }  class MyThread4 extends Thread { 	@Override 	public void run() { 		for (int i = 0; i <= 100; i++) { 			System.out.println(getName() + "@" + i); 		} 	} } 

线程安全

线程加锁是为了避免超卖问题,或者卖出同一张票的问题

加锁的方式有两种:

Synchronized锁

//线程安全  //多个线程实现先后依次访问共享的资源,解决线程安全 //加锁:每次只允许一个线程加锁,加锁后才可以访问资源,访问完毕后释放锁资源, //其他线程才可以抢占资源  //方案1:同步代码块,注意传入的锁的对象一定是唯一的 //synchronized(同步锁) { //	//共享的资源 //}  //方案2:同步方法,将访问的共享资源的核心方法上锁,以此来保证线程安全 //修饰符 synchronized 返回值类型 方法名(方法参数) { //	 //}  //锁对象不能自己指定: //	普通方法锁对象:this //	静态方法锁对象:当前类的字节码文件对象 

Lock锁

//方案3:为了更加清晰的表示如何加锁和解锁,JDK5以后提供了一个新的锁对象Lock //获取锁:void lock()获得锁,然后获得资源 //释放锁:void unlock()释放锁,然后释放资源 

Demo01

package day31_线程安全;  public class MyThread extends Thread { 	// 表示此成员变量为所有的对象共享 	static int ticket = 0 ; 	// 锁对象唯一 	static Object obj = new Object();  	public MyThread(String string) { 		super(string); 	}  	// 线程在执行过程中,cpu的执行权可能随时会被抢走 	@Override 	public void run() { //		synchronized (obj) { 		while (true) { 			// 锁对象一定要唯一 			synchronized (obj) { //			synchronized (MyThread.class) { 				if (ticket >= 1000) { 					break; 				} 				ticket++; 				System.out.println(getName() + "正在卖票" + ticket + "张"); 			} 		} 	} } 
package day31_线程安全; //线程加锁是为了防止超卖问题、或者卖出同一张票的问题 //加锁的方式有两种:关键字Synchronized,Lock对象 public class Demo01 { 	public static void main(String[] args) { 		MyThread t1 = new MyThread("窗口1"); 		MyThread t2 = new MyThread("窗口2"); 		MyThread t3 = new MyThread("窗口3");  		t1.start(); 		t2.start(); 		t3.start(); 	} } 

Demo02

package day31_线程安全; public class Demo02 { 	public static void main(String[] args) { 		MyThread2 t1 = new MyThread2("窗口1"); 		MyThread2 t2 = new MyThread2("窗口2"); 		MyThread2 t3 = new MyThread2("窗口3");  		t1.start(); 		t2.start(); 		t3.start(); 	} } 
package day31_线程安全;  public class MyThread2 extends Thread { 	// 表示此成员变量为所有的对象共享 	static int ticket;  	public MyThread2(String string) { 		super(string); 	}  	// 线程在执行过程中,cpu的执行权可能随时会被抢走 	@Override 	public void run() { 		while (true) { 			if (method()) { 				break; 			} 		} 	}  	public static synchronized boolean method() { 		if (ticket >= 1000) { 			return true; 		} 		try { 			Thread.sleep(10); 		} catch (InterruptedException e) { 			// TODO Auto-generated catch block 			e.printStackTrace(); 		} 		ticket++; 		System.out.println(Thread.currentThread().getName() + "正在卖票" + ticket + "张"); 		return false; 	} } 

Demo03

package day31_线程安全;  public class Demo03 { 	public static void main(String[] args) { 		MyRun m1 = new MyRun(); 		 		Thread t1 = new Thread(m1, "窗口1"); 		Thread t2 = new Thread(m1, "窗口2"); 		Thread t3 = new Thread(m1, "窗口3");  		t1.start(); 		t2.start(); 		t3.start(); 	} } 
package day31_线程安全;  public class MyRun implements Runnable { 	// 表示此成员变量为所有的对象共享 	static int ticket; 	// 线程在执行过程中,cpu的执行权可能随时会被抢走 	@Override 	public void run() { 		while (true) { 			if (method()) { 				break; 			} 		} 	}  	public synchronized boolean method() { 		if (ticket >= 2000) { 			return true; 		} 		try { 			Thread.sleep(10); 		} catch (InterruptedException e) { 			// TODO Auto-generated catch block 			e.printStackTrace(); 		} 		ticket++; 		System.out.println(Thread.currentThread().getName() + "正在卖票" + ticket + "张"); 		return false; 	} } 

Demo04

package day31_线程安全;  public class Demo04 { 	public static void main(String[] args) { 		MyThread3 t1 = new MyThread3("窗口1"); 		MyThread3 t2 = new MyThread3("窗口2"); 		MyThread3 t3 = new MyThread3("窗口3");  		t1.start(); 		t2.start(); 		t3.start(); 	} } 
package day31_线程安全;  import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;  public class MyThread3 extends Thread { 	// 表示此成员变量为所有的对象共享 	static int ticket; 	static Lock lock = new ReentrantLock();  	public MyThread3(String string) { 		super(string); 	}  	// 线程在执行过程中,cpu的执行权可能随时会被抢走 	@Override 	public void run() { 		while (true) { 			try { 				lock.lock(); 				if (ticket >= 2000) { 					break; 				} 				try { 					Thread.sleep(10); 				} catch (InterruptedException e) { 					// TODO Auto-generated catch block 					e.printStackTrace(); 				} 				ticket++; 				System.out.println(Thread.currentThread().getName() + "正在卖票" + ticket + "张"); 			} finally { 				lock.unlock(); 			} 		} 	}  } 

线程状态及常用方法

在Java程序中,一个线程对象通过调用start()方法启动线程,并且在线程获取CPU时,自动执行run()方法。run()方法执行完毕,代表线程的生命周期结束。
●在整个线程的生命周期中,线程的状态有以下6种:

○New:新建状态,新创建的线程,此时尚未调用start()方法;
○Runnable:运行状态,运行中的线程,已经调用start()方法,线程正在或即将执行run()方法;
○Blocked:阻塞状态,运行中的线程,在等待竞争锁时,被阻塞,暂不执行;
○Waiting:等待状态,运行中的线程,因为join()等方法调用,进入等待;
○Timed Waiting:计时等待状态,运行中的线程,因为执行sleep(等待毫秒值)join(等待毫秒值)等方法,进入计时等待;
○Terminated:终止状态,线程已终止,因为run()方法执行完毕。

●当线程启动后,它可以在Runnable、Blocked、Waiting和Timed Waiting这几个状态之间切换,直到最后变成Terminated状态,线程终止

线程终止的原因有:
○线程正常终止:run()方法执行到return语句返回;
○线程意外终止:run()方法因为未捕获的异常导致线程终止;
○对某个线程的Thread实例调用stop()方法强制终止(宇宙超级无敌强烈不推荐);

image.png

NEW新建状态

package day31_线程状态; //NEW //新线程创建出来,还没有调用start方法,此时状态为新建状态 public class New { 	public static void main(String[] args) { 		Thread t1 = new Thread() { 			@Override 			public void run() { 				System.out.println("子线程正在执行任务"); 			} 		}; 		System.out.println(t1.getState()); 	} } 

RUNNABLE可运行状态

package day31_线程状态; //RUNNABLE //线程对象调用start方法,等待Cpu分配资源RUNNABLE状态 public class Runable { 	public static void main(String[] args) { 		Thread t1 = new Thread() { 			@Override 			public void run() { 				System.out.println("子线程正在执行任务"); 			} 		}; 		t1.start(); 		System.out.println(t1.getState()); 	} } 

TERMINATED终止状态

package day31_线程状态;  //TERMINATED终止状态,run()方法执行完毕,操作系统可能已经注销了此线程 public class Terminated { 	public static void main(String[] args) throws InterruptedException { 		Thread t1 = new Thread() { 			@Override 			public void run() { 				System.out.println("子线程正在执行任务"); 			} 		}; 		t1.start(); 		Thread.sleep(1000); 		System.out.println(t1.getState()); 	} } 

WAITING等待状态

package day31_线程状态;  //WAITING等待状态 wait() join() public class WaitingState01 { 	public static void main(String[] args) throws InterruptedException { 		Runnable run = new Runnable() { 			Object obj = new Object();  			@Override 			public void run() { 				synchronized (obj) { 					try { 						obj.wait();// 等待 					} catch (InterruptedException e) { 						// TODO Auto-generated catch block 						e.printStackTrace(); 					} 				} 			} 		}; 		Thread t1 = new Thread(run); 		t1.start(); 		Thread.sleep(1000); 		System.out.println(t1.getState()); 	} } 
package day31_线程状态;  //WAITING等待状态 public class WaitingState02 { 	public static void main(String[] args) throws InterruptedException { 		Thread t1 = new Thread() { 			@Override 			public void run() { 				while (true) {  				} 			} 		}; 		t1.start(); 		// t1线程插队到当前的主线程的前面,主线程处于等待状态 		System.out.println("111"); 		t1.join(); 		System.out.println("222"); 		// 获取不到,因为当前的主线程被t1线程给插队,t1为死循环,无法结束任务,主线程处于WATTING状态 		System.out.println(Thread.currentThread().getState()); 	} } 
package day31_线程状态; //WAITING状态 等待状态 wait() join()  //wait() //1.和synchronized同时存在 //2.锁对象和调用wait方法的需要是同一个  //notify() 唤醒--锁对象的让等待的对象 public class WaitingState03 { 	public static void main(String[] args) throws InterruptedException { 		Object object = new Object(); 		Runnable run = new Runnable() { 			@Override 			public void run() { 				synchronized (this) { 					try { 						this.wait(); 					} catch (InterruptedException e) { 						// TODO Auto-generated catch block 						e.printStackTrace(); 					} 					System.out.println("正在执行"); 				} 			} 		}; 		Thread t1 = new Thread(run); 		t1.start(); 		Thread.sleep(1000); 		System.out.println(t1.getState()); 	} } 

BLOCKED阻塞状态

package day31_线程状态; //BLOCKED public class Blocked { 	public static void main(String[] args) throws InterruptedException { 		Runnable run = new Runnable() { 			@Override 			public void run() { 				synchronized (this) { 					// 死循环 					while(true){ 						 					} 				} 			} 		}; 		// 创建线程t1和t2并启动子线程 		Thread t1 = new Thread(run, "子线程1"); 		Thread t2 = new Thread(run, "子线程2"); 		 		t1.start(); 		t2.start(); 		// 主线程休眠,让t1和t2同时竞争一个锁资源 		Thread.sleep(1000); 		System.out.println(t1.getName() + t1.getState()); 		System.out.println(t2.getName() + t2.getState()); 	} } 

TIMED_WAITING计时等待状态

package day31_线程状态;  //sleep() 不释放锁资源 //wait()  释放锁资源 public class Timed_Waiting01 { 	public static void main(String[] args) throws InterruptedException { 		Runnable run = new Runnable() { 			@Override 			public void run() { 				synchronized (this) { 					try { 						Thread.sleep(5000); //						this.wait(5000); 					} catch (InterruptedException e) { 						// TODO Auto-generated catch block 						e.printStackTrace(); 					} 				} 			} 		}; 		Thread t1 = new Thread(run, "线程1"); 		Thread t2 = new Thread(run, "线程2"); 		t1.start(); 		t2.start(); 		// 让主线程等待 		Thread.sleep(1000); 		System.out.println(t1.getName() + t1.getState()); 		System.out.println(t2.getName() + t2.getState()); 	} } 
package day31_线程状态;  //TIMED_WAITING 线程计时等待状态 //join(参数),可以将线程切换为计时等待状态 //sleep() 不释放锁资源 //wait()  释放锁资源  public class Timed_Waiting02 { 	public static void main(String[] args) throws InterruptedException { 		Thread t1 = new Thread() { 			@Override 			public void run() { 				Thread t2 = new Thread() { 					@Override 					public void run() { 						while (true) {  						} 					} 				}; 				t2.start(); 				System.out.println("t2的状态计时等待前" + t2.getState()); 				// join方法让当前线程处于计时等待 				try { 					t2.join(5000 * 1000); 					System.out.println("t2的状态计时等待后" + t2.getState()); 				} catch (InterruptedException e) { 					// TODO Auto-generated catch block 					e.printStackTrace(); 				} 			} 		}; 		t1.start(); 		Thread.sleep(1000); 		System.out.println("t1的状态" + t1.getState()); 	} } 

线程池

线程池内部维护了若干个线程,没有任务的时候,这些线程都处于等待空闲状态。如果有新的线程任务,就分配一个空闲线程执行。如果所有线程都处于忙碌状态,线程池会创建一个新线程进行处理或者放入队列(工作队列)中等待。

┌─────┐ execute  ┌──────────────────┐ │Task1│─────────>ThreadPool        │ ├─────┤          │┌───────┐┌───────┐│ │Task2│          ││Thread1││Thread2││ ├─────┤          │└───────┘└───────┘│ │Task3│          │┌───────┐┌───────┐│ ├─────┤          ││Thread3││Thread4││ │Task4│          │└───────┘└───────┘│ ├─────┤          └──────────────────┘ │Task5│ ├─────┤ │Task6│ └─────┘   ... 

线程池常用类和接口

在Java标准库提供了如下几个类或接口,来操作并使用线程池:
1.ExecutorService接口:进行线程池的操作访问;
2.Executors类:创建线程池的工具类;
3.ThreadPoolExecutor及其子类:封装线程池的核心参数和运行机制;

线程池的基本使用方式

// 线程池基本使用方式 // 创建一个ThreadPoolExecutor类型的对象,代表固定大小的线程池 ExecutorService executor = Executors.newFixedThreadPool(3); // 该线程池拥有3个线程  // 执行线程任务 executor.execute(task1); executor.execute(task2); executor.execute(task3); executor.execute(task4); executor.execute(task5);  // 使用结束后,使用shutdown关闭线程池 executor.shutdown(); 

线程池的常见方法

● 执行无返回值的线程任务:void execute(Runnable command);
● 提交有返回值的线程任务:Future submit(Callable task);
● 关闭线程池:void shutdown(); 或 shutdownNow();
● 等待线程池关闭:boolean awaitTermination(long timeout, TimeUnit unit);

执行线程任务

execute()和submit()提交任务时的区别?

execute()只能提交Runnable类型的任务,没有返回值,而submit()既能提交Runnable类型任务也能提交Callable类型任务,可以返回Future类型结果,用于获取线程任务执行结果。
execute()方法提交的任务异常是直接抛出的,而submit()方法是捕获异常,当调用Future的get()方法获取返回值时,才会抛出异常。

// 计算1-100w的之间所有数字的累加和,每10w个数字交给1个线程处理 // 创建一个固定大小的线程池: ExecutorService executorService = Executors.newFixedThreadPool(4);  // 创建集合,用于保存Future执行结果 List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();  // 每10w个数字,封装成一个Callable线程任务,并提交给线程池 for (int i = 0; i <= 900000; i += 100000) {     Future<Integer> result = executorService.submit(new CalcTask(i+1, i + 100000));     futureList.add(result); }  // 处理线程任务执行结果 try {     int result = 0;     for (Future<Integer> f : futureList) {         result += f.get();     }     System.out.println("最终计算结果" + result); } catch (InterruptedException e) {     e.printStackTrace(); } catch (ExecutionException e) {     e.printStackTrace(); }  // 关闭线程池 pool.shutdown(); 

关闭线程池

线程池在程序结束的时候要关闭。

①使用shutdown()方法关闭线程池的时候,它会等待正在执行的任务先完成,然后再关闭。  ②shutdownNow()会立刻停止正在执行的任务;  ③使用awaitTermination()方法时,主线程会处于一种等待的状态,按照指定的timeout检查线程池。 第一个参数指定的是时间,  第二个参数指定的是时间单位(当前是秒)。返回值类型为boolean型。 如果等待的时间超过指定的时间,但是线程池中的线程运行完毕,awaitTermination()返回true。 如果等待的时间超过指定的时间,但是线程池中的线程未运行完毕,awaitTermination()返回false。 如果等待时间没有超过指定时间,则继续等待。 该方法经常与shutdown()方法配合使用,用于检测线程池中的任务是否已经执行完毕: 

线程池的执行流程

1.提交一个新线程任务,线程池会在线程池中分配一个空闲线程,用于执行线程任务;
2.如果线程池中不存在空闲线程,则线程池会判断当前“存活的线程数”是否小于核心线程数corePoolSize。
○如果小于核心线程数corePoolSize,线程池会创建一个新线程(核心线程)去处理新线程任务;
○如果大于核心线程数corePoolSize,线程池会检查工作队列;
■如果工作队列未满,则将该线程任务放入工作队列进行等待。线程池中如果出现空闲线程,将从工作队列中按照FIFO的规则取出1个线程任务并分配执行;
■如果工作队列已满,则判断线程数是否达到最大线程数maximumPoolSize;
●如果当前“存活线程数”没有达到最大线程数maximumPoolSize,则创建一个新线程(非核心线程)执行新线程任务;
●如果当前“存活线程数”已经达到最大线程数maximumPoolSize,直接采用拒绝策略处理新线程任务;

综上所述,执行顺序为:核心线程、工作队列、非核心线程、拒绝策略。

image.png

线程池的配置参数

	参数1:int corePoolSize, 指定线程池的核心线程数量   正式员工 	参数2:int maximumPoolSize, 指定线程池的最大线程数量  正式员工  临时工 	参数3:long keepAliveTime,  指定临时线程的最大存活时间  临时工空闲多久被开除 	参数4:TimeUnit unit, 临时线程最大的存活时间单位 	参数5:BlockingQurue workQueue,  指定线程池的任务队列(客户排队的地方) 	参数6:ThreadFactory threadFactory, 指定线程工厂(负责招聘员工的hr) 	参数7:RejectedExecutionHandler handler  线程池的拒绝策略 

参数1corePoolSize线程池核心线程数:也可以理解为线程池维护的最小线程数量,核心线程创建后不会被回收。大于核心线程数的线程,在空闲时间超过keepAliveTime后会被回收;
在创建了线程池后,默认情况下,线程池中并没有任何线程,当调用 execute() 方法添加一个任务时,如果正在运行的线程数量小于corePoolSize,则马上创建新线程并运行这个任务。
IO密集计算:由于 I/O 设备的速度相对于 CPU来说都很慢,所以大部分情况下,I/O 操作执行的时间相对于 CPU 计算来说都非常长,这种场景我们一般都称为 I/O 密集型计算。最佳线程数 =CPU 核数 * [ 1 +(I/O 耗时 / CPU 耗时)]。
CPU密集型:CPU 密集型计算大部分场景下都是纯 CPU 计算,多线程主要目的是提升CPU利用率,最佳线程数 =“CPU 核心数 +1”。这样的话,当线程因为偶尔的内存页失效或其他原因导致阻塞时,这个额外的线程可以临时替补,从而保证 CPU 的利用率。

参数2maximumPoolSize线程池最大线程数:线程池允许创建的最大线程数量;(包含核心线程池数量)
参数3keepAliveTime非核心线程线程存活时间:当一个可被回收的线程的空闲时间大于keepAliveTime,就会被回收。
当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会被回收,直到线程池中的线程数不超过corePoolSize。
如果设置allowCoreThreadTimeOut = true,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

参数4TimeUnit时间单位:参数keepAliveTime的时间单位;
参数5BlockingQueue阻塞工作队列:用来存储等待执行的任务;
参数6ThreadFactory线程工厂 : 用于创建线程,以及自定义线程名称,需要实现ThreadFactory接口;
参数7RejectedExecutionHandler拒绝策略:当线程池线程内的线程耗尽,并且工作队列达到已满时,新提交的任务,将使用拒绝策略进行处理;

四种拒绝策略

ThreadPoolExecutor.AbortPolicy:默认策略,丢弃任务并抛出RejectedExecutionException异常;
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常;
ThreadPoolExecutor.DiscardOldestPolicy:丢弃工作队列中的队头任务(即最旧的任务,也就是最早进入队列的任务)后,继续将当前任务提交给线程池;
ThreadPoolExecutor.CallerRunsPolicy:由原调用线程处理该任务 (谁调用,谁处理);

线程池的优点

1.提高响应速度
2.降低线程的可管理行
3.降低资源消耗(线程执行完后,不销毁,可以执行其他的任务)

创建线程池的方式

创建无上限的线程池
线程池是一个可以复用线程的技术
ExecutorService
方式1:Executors工具类创建线程对象
FixedThreadPool

package day31_线程池;  import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;  public class Demo02 { 	public static void main(String[] args) throws InterruptedException { 		// 获取有上限的线程池对象 		// 计算密集型任务:核心线程数量=CPU核数+1 		// IO密集型任务:CPU*2 		ExecutorService pool1 = Executors.newFixedThreadPool(3); 		// 提交任务 		pool1.submit(new MyRunnable()); 		Thread.sleep(1000); 		System.out.println("=========1========="); 		pool1.submit(new MyRunnable()); 		Thread.sleep(1000); 		System.out.println("=========2========="); 		pool1.submit(new MyRunnable()); 		Thread.sleep(1000); 		System.out.println("=========3========="); 		pool1.submit(new MyRunnable()); 		Thread.sleep(1000); 		System.out.println("=========4========="); 		pool1.submit(new MyRunnable());  		pool1.shutdown(); 	} } 

​ CachedThreadPool

package day31_线程池;  import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;  //创建无上限的线程池 //线程池是一个可以复用线程的技术 //ExecutorService //方式1:Executors工具类创建线程对象 public class Demo01 { 	public static void main(String[] args) throws InterruptedException {  		// 获取线程池 		ExecutorService pool = Executors.newCachedThreadPool(); 		// 提交线程任务 		pool.submit(new MyRunnable()); 		pool.submit(new MyRunnable()); 		pool.submit(new MyRunnable()); 		pool.submit(new MyRunnable()); 		Thread.sleep(1000);// 线程休眠1秒,体现复用 		System.out.println("============"); 		pool.submit(new MyRunnable());  		// 关闭线程池 		pool.shutdown(); 	} } 

​ SingleThreadExecutor

package day32_线程池;  import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;  public class Demo04 { 	public static void main(String[] args) { 		//单例线程池 单独线程的ThreadPoolExecutor对象 		ExecutorService pool = Executors.newSingleThreadExecutor(); 		 		pool.execute(new MyRun()); 		pool.execute(new MyRun()); 		pool.execute(new MyRun()); 		pool.execute(new MyRun()); 		pool.execute(new MyRun()); 	}  }  

​ ScheduledThreadPool

package day32_线程池;  import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit;  public class Demo05 { 	public static void main(String[] args) { 		// 能实现定时、周期性任务的线程池 		Runnable run = new Runnable() { 			@Override 			public void run() { 				System.out.println(Thread.currentThread().getName()); 			} 		}; 		ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); 		// 延时5秒执行任务 		// 参数1:任务 2:延时多久 3:时间单位 //		pool.schedule(run, 5, TimeUnit.SECONDS);  		// 延时5秒执行此任务,后每过3秒重复执行此任务 		pool.scheduleAtFixedRate(run, 5, 3, TimeUnit.SECONDS); 		 		pool.shutdown(); 	} } 

方式2:ThreadPoolExecutor

package day32_线程池;  public class MyRun implements Runnable { 	@Override 	public void run() { 		System.out.println(Thread.currentThread().getName() + "正在执行"); //		try { //			//线程执行的时间长一点,便于结果的观察 //			Thread.sleep(Integer.MAX_VALUE); //		} catch (InterruptedException e) { //			// TODO Auto-generated catch block //			e.printStackTrace(); //		} 	} } 
package day32_线程池;  import java.util.concurrent.Callable;  public class MyCall implements Callable<Integer> { 	private int n;  	public MyCall(int n) { 		this.n = n; 	}  	@Override 	public Integer call() throws Exception { 		int sum = 0; 		for (int i = 0; i <= n; i++) { 			sum += i; 		} 		return sum; 	}  }  

01

package day32_线程池;  import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; //创建无上限的线程池 //线程池是一个可以复用线程的技术 //ExecutorService //方式1:Executors工具类创建线程对象 //	FixedThreadPool //	CachedThreadPool //	SingleThreadExecutor //	ScheduledThreadPool //方式2:ThreadPoolExecutor //参数1:int corePoolSize, 指定线程池的核心线程数量   正式员工 //参数2:int maximumPoolSize, 指定线程池的最大线程数量  正式员工  临时工 //参数3:long keepAliveTime,  指定临时线程的最大存活时间  临时工空闲多久被开除 //参数4:TimeUnit unit, 临时线程最大的存活时间单位 //参数5:BlockingQurue workQueue,  指定线程池的任务队列(客户排队的地方) //参数6:ThreadFactory threadFactory, 指定线程工厂(负责招聘员工的hr) //参数7:RejectedExecutionHandler handler  线程池的拒绝策略  //四种拒绝策略: //AbortPolicy() 丢弃当前线程任务并抛出异常,是默认的策略 //DiscardPolicy() 丢弃当前线程任务但不抛出异常[不推荐的做法] //DiscardOldestPolicy() 丢弃等待队列中的最老的线程任务,然后将当前任务添加到队列中 //CallerRunsPolicy() 直接由"当前调用线程"直接执行该线程任务,绕过线程池直接执行  //线程池优点: //1.提高响应速度 //2.降低线程的可管理行 //3.降低资源消耗(线程执行完后,不销毁,可以执行其他的任务) public class Demo01 { 	public static void main(String[] args) throws InterruptedException { //		参数1:int corePoolSize, 指定线程池的核心线程数量   正式员工 //		参数2:int maximumPoolSize, 指定线程池的最大线程数量  正式员工  临时工 //		参数3:long keepAliveTime,  指定临时线程的最大存活时间  临时工空闲多久被开除 //		参数4:TimeUnit unit, 临时线程最大的存活时间单位 //		参数5:BlockingQurue workQueue,  指定线程池的任务队列(客户排队的地方) //		参数6:ThreadFactory threadFactory, 指定线程工厂(负责招聘员工的hr) //		参数7:RejectedExecutionHandler handler  线程池的拒绝策略 		ExecutorService pool1 = new ThreadPoolExecutor(3, 6, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), 				Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); 		 		// 2.提交任务 		MyRun run = new MyRun(); 		pool1.submit(run);// 提交任务给线程池对象,线程池会自动的创建一个新的线程,自动处理任务 		pool1.submit(run); 		pool1.submit(run);  		pool1.submit(run);// 提交第4个任务时,没有达到临时线程的创建条件,复用核心线程,执行此任务 		pool1.submit(run);// 提交第5个任务时,没有达到临时线程的创建条件,复用核心线程,执行此任务 		pool1.submit(run);// 提交第6个任务时,核心线程满,队列也满  //		Thread.sleep(1000);//任务短  		pool1.submit(run);// 提交第7个任务时,创建临时线程1 		pool1.submit(run);// 提交第8个任务时,创建临时线程2 		pool1.submit(run);// 提交第9个任务时,创建临时线程3 此时核心线程满,队列也满,临时线程满  		pool1.submit(run);// 再来新的任务会进行拒绝策略 		pool1.submit(run);// 再来新的任务会进行拒绝策略 		pool1.submit(run);// 再来新的任务会进行拒绝策略  		// 等线程池中的内容执行完毕关闭线程池,不接收新任务,但仍处理工作队列中的任务 		pool1.shutdown();  		// 立即关闭线程池,不接收新任务,同时中断正在执行的任务 //		pool1.shutdownNow(); 	} } 

02

package day32_线程池;  import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; //创建无上限的线程池 //线程池是一个可以复用线程的技术 //ExecutorService //方式1:Executors工具类创建线程对象 //方式2:ThreadPoolExecutor  //四种拒绝策略: //AbortPolicy() 丢弃当前线程任务并抛出异常,是默认的策略 //DiscardPolicy() 丢弃当前线程任务但不抛出异常[不推荐的做法] //DiscardOldestPolicy() 丢弃等待队列中的最老的线程任务,然后将当前任务添加到队列中 //CallerRunsPolicy() 直接由"当前调用线程"直接执行该线程任务,绕过线程池直接执行  //线程池优点: //1.提高响应速度 //2.降低线程的可管理行 //3.降低资源消耗(线程执行完后,不销毁,可以执行其他的任务) public class Demo02 { 	public static void main(String[] args) throws InterruptedException, ExecutionException { //		参数1:int corePoolSize, 指定线程池的核心线程数量   正式员工 //		参数2:int maximumPoolSize, 指定线程池的最大线程数量  正式员工  临时工 //		参数3:long keepAliveTime,  指定临时线程的最大存活时间  临时工空闲多久被开除 //		参数4:TimeUnit unit, 临时线程最大的存活时间单位 //		参数5:BlockingQurue workQueue,  指定线程池的任务队列(客户排队的地方) //		参数6:ThreadFactory threadFactory, 指定线程工厂(负责招聘员工的hr) //		参数7:RejectedExecutionHandler handler  线程池的拒绝策略 		ExecutorService pool1 = new ThreadPoolExecutor(3, 6, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), 				Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());  		// 2.提交任务 		Future f1 = pool1.submit(new MyCall(5)); 		Future f2 = pool1.submit(new MyCall(100)); 		Future f3 = pool1.submit(new MyCall(200)); 		Future f4 = pool1.submit(new MyCall(300)); 		Future f5 = pool1.submit(new MyCall(400)); 		Future f6 = pool1.submit(new MyCall(500)); 		System.out.println(f1.get()); 		System.out.println(f2.get()); 		System.out.println(f3.get()); 		System.out.println(f4.get());  		pool1.execute(new MyRun()); 		pool1.execute(new MyRun()); 		pool1.execute(new MyRun()); 		  		// 等线程池中的内容执行完毕关闭线程池,不接收新任务,但仍处理工作队列中的任务 		pool1.shutdown(); 	} } 

03

package day32_线程池;  import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; //创建无上限的线程池 //线程池是一个可以复用线程的技术 //ExecutorService //方式1:Executors工具类创建线程对象 //方式2:ThreadPoolExecutor  //四种拒绝策略: //AbortPolicy() 丢弃当前线程任务并抛出异常,是默认的策略 //DiscardPolicy() 丢弃当前线程任务但不抛出异常[不推荐的做法] //DiscardOldestPolicy() 丢弃等待队列中的最老的线程任务,然后将当前任务添加到队列中 //CallerRunsPolicy() 直接由"当前调用线程"直接执行该线程任务,绕过线程池直接执行  //线程池优点: //1.提高响应速度 //2.降低线程的可管理行 //3.降低资源消耗(线程执行完后,不销毁,可以执行其他的任务) public class Demo03 { 	public static void main(String[] args) throws InterruptedException, ExecutionException { //		参数1:int corePoolSize, 指定线程池的核心线程数量   正式员工 //		参数2:int maximumPoolSize, 指定线程池的最大线程数量  正式员工  临时工 //		参数3:long keepAliveTime,  指定临时线程的最大存活时间  临时工空闲多久被开除 //		参数4:TimeUnit unit, 临时线程最大的存活时间单位 //		参数5:BlockingQurue workQueue,  指定线程池的任务队列(客户排队的地方) //		参数6:ThreadFactory threadFactory, 指定线程工厂(负责招聘员工的hr) //		参数7:RejectedExecutionHandler handler  线程池的拒绝策略  		// 参数6:线程工厂自定义线程名称 		ThreadFactory factory = new ThreadFactory() { 			private int count = 1;  			@Override 			public Thread newThread(Runnable r) { 				Thread thread = new Thread(r, "线程名-" + count++); 				return thread; 			} 		}; 		// 参数7:线程池的拒绝策略定义 		RejectedExecutionHandler policy = new RejectedExecutionHandler() { 			@Override 			public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 				System.out.println("任务" + r + "线程满队列满不能执行了"); 			} 		}; 		ExecutorService pool1 = new ThreadPoolExecutor(3, 6, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), factory, 				policy);  		// 2.提交任务 		MyRun run = new MyRun(); 		pool1.submit(run);// 提交任务给线程池对象,线程池会自动的创建一个新的线程,自动处理任务 		pool1.submit(run); 		pool1.submit(run);  		pool1.submit(run);// 提交第4个任务时,没有达到临时线程的创建条件,复用核心线程,执行此任务 		pool1.submit(run);// 提交第5个任务时,没有达到临时线程的创建条件,复用核心线程,执行此任务 		pool1.submit(run);// 提交第6个任务时,核心线程满,队列也满  //		Thread.sleep(1000);//任务短  		pool1.submit(run);// 提交第7个任务时,创建临时线程1 		pool1.submit(run);// 提交第8个任务时,创建临时线程2 		pool1.submit(run);// 提交第9个任务时,创建临时线程3 此时核心线程满,队列也满,临时线程满  		pool1.submit(run);// 再来新的任务会进行拒绝策略 		// 等线程池中的内容执行完毕关闭线程池,不接收新任务,但仍处理工作队列中的任务 		pool1.shutdown(); 	} } 

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!