`
oham_一1一
  • 浏览: 51421 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java线程基础——线程池使用示例

阅读更多

引言

合理利用线程池能够带来三个好处:

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

 

本篇参考:http://www.infoq.com/cn/articles/java-threadPool

                  http://www.cjsdn.net/Doc/JDK60/

 

关于线程池的配置参数

Java中创建线程池创建如下:

ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

 ThreadPoolExecutor的构造函数有多个,通过构造函数的参数配置线程池,以下是各个参数的说明:

corePoolSize:线程池的基本大小,maximumPoolSize:线程池最大大小,即线程池允许创建的最大线程数,线程池会根据corePoolSize(调用getCorePoolSize())和maximumPoolSize(调用getMaximumPoolSize())去自动调整池中的线程数量(调用getPoolSize())。当池中的线程数少于corePoolSize的时候,会创建新的线程放到任务队列处理请求,不管队列中其他的线程是否空闲;当线程数大于coolPoolSize而小于maximumPoolSize的时候,如果池中任务队列为空,则创建线程放入任务队列。当设置maximumPoolSize为Integer.MAX_VALUE,则这个线程池为无界线程池,然后池中的线程数量是任意的。如果任务队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务,该线程等待进入任务队列。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。(鄙人估计corePoolSize确定了任务队列的大小)

 

workQueue:任务队列,用于转移和阻塞提交了的任务,即任务队列是运行线程的,任务队列根据corePoolSize和maximumPoolSize工作:

   1.当正在运行的线程小于coolPoolSize,线程池会创建新的线程。

   2.当大于coolPoolSize而任务队列未满,则从队列里拿一个空闲的线程去接任务。

   3.当大于coolPoolSize而任务队列满了(即队列中没有空闲的线程),并且小于maximumPoolSize,会创建新的线程接任务,该线程等待进入任务队列。

   4.当大于maximumPoolSize,该任务会根据handler(RejectedExecutionHandler,饱和策略)处理。

参考图:

 任务队列又有以下集中策略模式:

    1.直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。    

    2.无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

  3. 有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。

 

handler:RejectedExecutionHandler(饱和策略),当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。

   1.在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时 RejectedExecutionException

   2.在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

   3.在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除。

   4.在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。

定义和使用其他种类的 RejectedExecutionHandler 类也是可能的,但这样做需要非常小心,尤其是当策略仅用于特定容量或排队策略时。

keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
unit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
threadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。如果没有另外说明,则在同一个 ThreadGroup 中一律使用 Executors.defaultThreadFactory() 创建线程,并且这些线程具有相同的 NORM_PRIORITY 优先级和非守护进程状态。通过提供不同的 ThreadFactory,可以改变线程的名称、线程组、优先级、守护进程状态,等等。如果从 newThread 返回 null 时 ThreadFactory 未能创建线程,则执行程序将继续运行,但不能执行任何任务。
 
钩子 (hook) 方法 
此类提供 protected 可重写的 beforeExecute(java.lang.Thread, java.lang.Runnable) 和 afterExecute(java.lang.Runnable, java.lang.Throwable) 方法,这两种方法分别在执行每个任务之前和之后调用。它们可用于操纵执行环境;例如,重新初始化 ThreadLocal、搜集统计信息或添加日志条目。此外,还可以重写方法 terminated() 来执行 Executor 完全终止后需要完成的所有特殊处理。   如果钩子 (hook) 或回调方法抛出异常,则内部辅助线程将依次失败并突然终止。队列维护   方法 getQueue() 允许出于监控和调试目的而访问工作队列。强烈反对出于其他任何目的而使用此方法。remove(java.lang.Runnable) 和 purge() 这两种方法可用于在取消大量已排队任务时帮助进行存储回收。
 
线程池的关闭
我们可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。但是它们存在一定的区别,shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。
 
总结
举个不太优雅的例子,将线程池比喻成一个窑子,每个任务都是嫖客,线程就是接待客人的妹子,一个任务一条线程(不搞多P),corePoolSize是坐台的妹子数,maximumPoolSize是妹子的总数,任务队列是排着正在ooxx的以及准备ooxx的其大小为一次最多只允许有多少对在ooxx,keepAliveTime是每个妹子最大工作时长,做完若没超过时长就是闲着的,从闲着的坐台妹子选出再接另外的,若没闲着的坐台妹子,再叫人数过来补充,但不能超过妹子总数,超过了的话按经营策略(RejectedExecutionHandler——策略处理,所以可以想象,窑子老板就想多赚,坐台的妹子只要还行,接着来,不会轻易给你个新鲜的因为有任务队列大小限制(房间有限,允许ooxx的对数不能太多),若队列满了,生意好,客人只能携着妹子等了。。。。大概意思是如此,给个图自己脑补一下:

 
 
以下是示例代码:
ThreadPoolGenerator.java,封装了ThreadPoolExecutor的创建:
package testThreadPool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolGenerator {

	private volatile static ThreadPoolExecutor threadPoolExecutor;
	
	//写了自己的一个Executor,主要是用于线程池执行完所有任务所需的时间,重写了terminated方法
	public static class MyThreadPoolExecutor extends ThreadPoolExecutor {

		long sTime = 0L;
		long eTime = 0L;
		
		public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
				long keepAliveTime, TimeUnit unit,
				BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
				RejectedExecutionHandler handler) {
			super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
					threadFactory, handler);
		}
		
		@Override
		protected void terminated() {
			super.terminated();
			if(sTime != 0l) {
				eTime = System.currentTimeMillis();
				System.out.println("executor completed tasks take: " + (eTime - sTime) + " ms");
			}
			
		}
		
		//记录Executor开始执行的那刻的时间
		public void startLogTime() {
			sTime = System.currentTimeMillis();
		}
	}
	
	public static ThreadPoolExecutor getThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			Long keepAliveTime, int quequeSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
		
		if(threadPoolExecutor == null) {
			synchronized (ThreadPoolGenerator.class) {
				if(threadPoolExecutor == null) {
					threadFactory = threadFactory == null ? Executors.defaultThreadFactory() : threadFactory;
					handler = handler == null ? new ThreadPoolExecutor.AbortPolicy() : handler;
					
					threadPoolExecutor = new MyThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
							TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(quequeSize), threadFactory, handler);
				}
			}
		}
		
		return threadPoolExecutor;
	}
}
TestTask.java, 一个测试任务类:
package testThreadPool;

public class TestTask implements Runnable{

	private String name;
	
	public TestTask(String name) {
		this.name = name;
	}
	
	
	//模拟任务,此处两个for 循环,若循环次数不大,那么有线程执行跟没线程执行效果差不多的
	public void performTask() {
		for(int i=0; i<100000000; i++){
			for(int j=0; j<1000000; j++) {
				j=i+j;
			}
		}
		
		System.out.println(name + " completed.");
	}

	//通过线程执行模拟任务
	@Override
	public void run() {
		this.performTask();
		
	}
}
 
TestCase.java,测试类:
package testThreadPool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

import testThreadPool.ThreadPoolGenerator.MyThreadPoolExecutor;


public class TestCase {

	
	public static void main(String[] args) {
		
		List<TestTask> tasks = new ArrayList<TestTask>();
		for(int i=1; i<=5; i++) 
			tasks.add(new TestTask("Task " + i));
		
		
		TestCase c = new TestCase();
		
		System.out.println("no thread case:");
		
		long sTime = System.currentTimeMillis();
		
		c.noThreadProcess(tasks);
		
		long eTime = System.currentTimeMillis();
		long tTime = eTime - sTime;
		System.out.println("process take :" + tTime + "ms");
		
		System.out.println("=========================");

		
		System.out.println();
		
		
		System.out.println("with thread case:");
		
		ThreadPoolExecutor executor = ThreadPoolGenerator.getThreadPoolExecutor(3, 5, 5000L, 3, null, null);
		
		c.withThreadProcess(executor, tasks);
		
		eTime = System.currentTimeMillis();
		
		System.out.println("=========================");
		
	}
	
	
	
	public void withThreadProcess(ThreadPoolExecutor executor, List<TestTask> list) {
		
		//此举用来启动记录执行耗时
		((MyThreadPoolExecutor)executor).startLogTime();
		
		for(TestTask task : list) {
			executor.execute(task);
		}
		executor.shutdown();
		
	}
	
	public void noThreadProcess(List<TestTask> list) {
		
		for(TestTask task : list) {
			task.performTask();
		}
		
	}

}
 测试结果:
no thread case:
Task 1 completed.
Task 2 completed.
Task 3 completed.
Task 4 completed.
Task 5 completed.
process take :2802ms
=========================

with thread case:
=========================
Task 3 completed.
Task 2 completed.
Task 1 completed.
Task 4 completed.
Task 5 completed.
executor completed tasks take: 1224 ms
 
 
 线程池另外一种用法,用线程池执行任务,完成后的取得执行结果:
TestMessageTask.java,那个badTask如果为true,表示为坏任务,模拟任务执行出错:
package testThreadPool;

import java.util.concurrent.Callable;

public class TestMessageTask implements Callable<String> {

	private String name;
	private boolean badTask;
	
	public TestMessageTask(String name, boolean badTask) {
		this.name = name;
		this.badTask = badTask;
	}
	
	@Override
	public String call() throws Exception {
		for(int i=0; i<100000000; i++){
			for(int j=0; j<1000000; j++) {
				j=i+j;
			}
		}
		
		//用了一个boolean,模拟执行出错的情形
		if(badTask) {
			throw new RuntimeException(name + " is bad task!!");
		}
		return name + " completed.";
	}

}
 
MessageThreadPoolExecutor.java:
package testThreadPool;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MessageThreadPoolExecutor extends ThreadPoolExecutor{

	
	//把父类的构造函数全弄出来算了。。。
	public MessageThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
	}

	public MessageThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
				threadFactory);
	}

	public MessageThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	public MessageThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
			RejectedExecutionHandler handler) {
		
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
				threadFactory, handler);
	}
	
	
	//定义了一个方法执行任务集合,用了泛型,表示结果类型由Callable类型的任务对象决定
	public <T> Map<String, T> performTasks(Map<String, Callable<T>> taskMap) throws InterruptedException{
		
		if(taskMap == null || taskMap.isEmpty()) 
			throw new NullPointerException();
		
		Map<String, Future<T>> futureMap = new HashMap<String, Future<T>>();
		Map<String, T> messageMap = new HashMap<String, T>();
		
		boolean done = false;
		
		try {
			
			for(String key : taskMap.keySet()) {
				/**
				 * 这里用了两种方式执行任务:execute与submit,建议翻翻API文档,
				 * 关于Future的get方法,没弄懂。。。
				 */
				//execute 方式
				/*RunnableFuture<T> futureTask = new FutureTask<T>(taskMap.get(key));
				execute(futureTask);
				futureMap.put(key, futureTask);*/
				
				
				//submit 方式
				futureMap.put(key, submit(taskMap.get(key)));
				
			}
			
			/**
			 *  再次遍历任务,逐个调用get方法,get方法会阻塞住直到任务完成,
			 *  get方法返回一个结果,根据结果判断任务执行成功与否,这也是我没有看懂
			 *  API的地方,那个submit方法明明说返回的Future对象如果成功它的get方法
			 *  返回null,但messageMap中的value是有的,不为null。。。 
			 */
			for(String key : futureMap.keySet()) {
				Future<T> f = futureMap.get(key);
				try {
					T result = f.get();
					messageMap.put(key, result);
				} catch (ExecutionException e) {
					System.out.println(e.getMessage());
				}
			}
			
			done = true;
			return messageMap;
		}finally {
			//若上面出了异常没done,没做完的任务直接cancel
			if(!done) {
				for(String key : futureMap.keySet()) {
					futureMap.get(key).cancel(true);
				}
			}
			
			this.shutdown();
		}
		
	}
	

}
 
测试代码,MsgTestCase.java:
package testThreadPool;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

public class MsgTestCase {

	public static void main(String[] args) {
		
		Map<String, Callable<String>>taskMap = new HashMap<String, Callable<String>>();
		for(int i=1; i<=5; i++) {
			
			//随机产生坏任务
			int r = (int)(Math.random()*5 + 1);
			boolean badTask = (i==r);
			
			taskMap.put("Task: " + i ,new TestMessageTask("Task: " + i, badTask));
		}
		
		
		MessageThreadPoolExecutor executor = new MessageThreadPoolExecutor(3, 5, 3000L, 
					TimeUnit.MILLISECONDS, 
					new ArrayBlockingQueue<Runnable>(2));
		
		try {
			Map<String, String> resultMap = executor.performTasks(taskMap);
			
			for(String key : resultMap.keySet()) {
				System.out.println(resultMap.get(key));
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} 
		
	}

}
 测试结果:
java.lang.RuntimeException: Task: 5 is bad task!!
java.lang.RuntimeException: Task: 2 is bad task!!
Task: 3 completed.
Task: 4 completed.
Task: 1 completed.
 
 
  • 大小: 64.4 KB
  • 大小: 13.2 KB
分享到:
评论

相关推荐

    轻量级java多线程池demo

    Java内置的`java.util.concurrent`包提供了一个强大的线程池实现——`ExecutorService`,通过`ThreadPoolExecutor`类可以自定义线程池配置。线程池通常包含核心线程数、最大线程数、线程空闲时间、工作队列等参数,...

    java常用的代码——线程

    - **使用ExecutorService和ThreadPoolExecutor**:这是一种高级的线程池管理机制,可以有效地管理和控制线程的数量及执行过程。 #### 3. 线程的状态及其转换 Java线程具有以下几种状态: - **新建状态(New)**:当...

    uThreadPool线程池示例(查找0-1亿之间的质数任务)

    总之,`uThreadPool线程池示例`是一个很好的学习资源,它演示了如何利用线程池处理大型计算任务,同时展示了多线程编程中的并发控制和任务调度。对于想要提升并发编程能力的开发者来说,这是一个值得研究的案例。

    Java多线程的小例子——吃包子

    这个名为"Java多线程的小例子——吃包子"的示例,旨在帮助开发者直观地理解多线程的工作原理。下面我们将深入探讨该示例所涉及的核心知识点。 首先,多线程通常涉及到以下几个关键概念: 1. **线程(Thread)**:...

    Java多线程下载网络图片

    在Java编程中,多线程是一项关键技能,尤其在处理并发任务时,如我们的示例——"Java多线程下载网络图片"。这个场景展示了如何利用多线程技术提高程序性能,减少用户等待时间,同时优化系统资源的使用。下面我们将...

    java多线程的使用和介绍

    - **Win32线程模型**:在Windows操作系统中,线程模型支持两种类型的线程——单线程模型(STA)和多线程模型(MTA)。STA线程通常用于UI相关的任务,而MTA线程则用于一般的计算任务。 - **Java中的线程模型**:Java...

    Java线程[文].pdf

    - **每个Java程序都使用线程** 事实上,每个Java应用程序至少包含两个线程——主线程和垃圾收集线程。主线程负责执行程序的入口点,而垃圾收集线程则自动管理内存。 - **为什么使用线程?** - **响应更快的UI** ...

    java学习教程——简洁易懂,一步步跟随即可上手学习

    Java是一种广泛使用的高级编程语言,尤其在企业级后端开发中占据着主导地位。本教程旨在为初学者提供一个简洁易懂的学习路径,让你能够快速上手并掌握Java编程技能。 1. **Java语言基础** - **变量与数据类型**:...

    Android(Java)之多线程结果返回——Future 、FutureTask、Callable、Runnable

    1. `Runnable`: 这是Java中最基础的多线程接口,只需实现`run()`方法,然后通过`Thread`对象启动新线程来执行这个任务。例如: ```java Runnable task = new Runnable() { @Override public void run() { // ...

    Java多线程入门介绍.pdf

    在深入探讨Java多线程之前,我们先来了解一些基本的概念——进程与线程。 - **进程**:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位。每个进程拥有独立的地址空间和其他资源。进程之间相互独立,...

    smoker_java多线程_

    标题"smoker_java多线程_"暗示我们将探讨的是一个关于Java多线程的示例,可能是解决某个特定的并发问题。描述中提到的"实现经典多线程问题中的多线程问题"进一步说明我们将深入研究一些常见的多线程挑战,例如死锁、...

    java多线程实现生产者消费者关系

    例如,可以使用`ThreadPoolExecutor`创建线程池,控制线程的并发数量,以及使用`Future`获取线程执行结果。 总之,理解并熟练掌握Java中的多线程和同步机制对于编写高效、可靠的并发程序至关重要。通过生产者消费者...

    多线程示例Test.jar

    3. 使用ExecutorService:Java 5引入的Executor框架,提供更灵活的线程管理,可以控制线程池大小,限制并发数量等。 三、Test.jar中的多线程示例 由于无法直接查看Test.jar的具体代码,我们只能根据其命名推测可能...

    java-ppt.rar_java .ppt_java ppt_java基础 ppt_java基础 ppt_ppt jav

    9. **多线程**:线程的创建(Thread类和Runnable接口),同步机制(synchronized关键字,wait(), notify(), notifyAll()方法),以及线程池的使用。 10. **枚举和注解**:枚举类型的应用,以及注解(Annotation)在...

    java面试——杭州-蚂蚁金服-资深工程师.zip

    4. **多线程**:线程的创建与同步,线程池的使用,死锁、活锁、饥饿等问题及解决方案。 5. **异常处理**:理解异常分类,如何编写正确的异常处理代码。 6. **IO/NIO/BIO**:I/O流的理解与应用,非阻塞IO模型NIO的...

    北大Java讲义——绝对经典

    《北大Java讲义》是北京大学计算机系精心编撰的一份教学资料...这份北大Java讲义深入讲解了以上各知识点,并辅以丰富的示例代码,无论你是初学者还是有一定经验的开发者,都能从中受益匪浅,提升对Java编程的掌握程度。

    java多线程机制PPT教案学习.pptx

    以下是一个简单的多线程示例,展示了两个线程——左手线程和右手线程——如何并发执行: ```java public class Example9_1 { public static void main(String[] args) { Lefthand left = new Lefthand(); Right...

    Java基础知识课堂代码core java知识全集

    Java提供了一种轻量级的并发机制——线程,通过Thread类和Runnable接口实现。线程可以共享同一块内存空间,通过同步机制(如synchronized关键字、volatile变量、wait()、notify()和notifyAll()方法)来防止数据竞争...

    JobAffinityThreadPool:一个示例线程池,它执行一组给定的作业。 此线程池具有Job Affinity,分配给具有相同作业ID的线程池的所有作业将由同一线程执行

    JobAffinityThreadPool是Java中一个特殊的线程池实现,它引入了一个独特的概念——任务亲和性。这个概念旨在优化特定类型的工作负载,确保具有相同标识(作业ID)的任务被同一个线程执行。这样的设计在某些场景下...

Global site tag (gtag.js) - Google Analytics