多线程基础篇(1)——初试线程

简介: 推荐书籍《Java并发编程的艺术》《Java编程思想》《Java核心技术卷一》,本文为个人学习笔记,删除一些不必要文字,并加入部分个人理解,日后复习较为简洁易懂

1.线程概念

1.1 线程与进程

    一个CPU在同一时间只能处理一个进程(程序),而一个进程包含至少一个或多个线程,操作系统会对每个进程分配相应的系统资源,如cpu,内存等,而进程中的所有线程将会共享这些资源。

    进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)

    线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)

1.2 并行与并发

    1.并行:真正意义上的同时运行

    2.并发:只是通过CPU的时间片分配算法来循环执行所有任务,cpu不断地切换执行线程,造成同时运行                   的错觉。

1.3 线程状态

    1)新建状态(New):新创建了一个线程对象。

    2)就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的进程除CPU之外,其它的运行所需资源都已全部获得。

    3)运行状态(Running):就绪状态的线程获取了CPU时间片,执行程序代码。

    4)阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

    5)终止:线程run方法中执行到return,或发生了一个未处理(try-catch)的异常时,则会发生线程终止。

    6)等待状态:表示当前线程进入等待状态,并且需要其他线程进行通知或中断。

    7)超时等待状态:表示当前线程进入等待状态,并且需要其他线程进行通知或中断,也可以在一定时间后自动返回

注:等待状态,超时等待状态实际上也算阻塞状态。

2.简单线程代码实现

2.1 通过继承Thread类创建

    继承Thread,重写run方法并在run方法中添加任务逻辑代码,即可创建一个线程。

public class Demo2{
	public static void main(String[] args) {
		for(int i=0;i<=20;i++){
			test t=new test(i);
			t.start();
			System.out.println("main thread"+i);
		}
		
	}
	
}
class test extends Thread{
	int i;
	public test(int i){
		this.i=i;
	}
	//重写run方法
	@Override
	public void run(){
		System.out.println("new thread"+i);
	}
}

2.2 实现Runnable接口

public class Demo3 {
	public static void main(String[] args) {
        //实现Runnable 接口
		Runnable r=new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		};
        //将Runnable对象作为参数传入Thread构造方法
		Thread t=new Thread(r);
		t.start();
	}
}

2.3 实现Callable接口

    这是一种特殊的方法,因为其可以获得返回值或者抛出异常,而Runnable与Thread皆不可以,但Callable线程任务对象只能交由线程池来执行。其返回值用Future对象来接收。

public class Demo5 {
	public static void main(String[] args) throws Exception {
		Callable<String> c=new Callable<String>() {
			@Override
			public String call() throws Exception {
				// TODO Auto-generated method stub
				return "callable";
			}
		};
		ExecutorService executors=Executors.newFixedThreadPool(5);
		Future<String> f=executors.submit(c);
		System.out.println(f.get());
	}
}

    使用Runnable,Callable接口实现对比继承Thread类的优点:

    1)实现了线程对象与线程任务的解耦

    2)避免了类的单继承问题,获得了更好的扩展性

2.4 线程池的简单使用

    与数据库连接池类似,我们通过一个线程池对象(执行器)来动态的生成管理线程对象,只需传入线程任务对象(Runnable,Callable),则线程池对象将自动的创建或者复用线程对象。

public class Demo4 {
	public static void main(String[] args) {
		//创建线程池对象,通过工厂类来创建线程池
		ExecutorService executors=Executors.newFixedThreadPool(5);//创建一个可重用的固定线程数的线程池
		Executors.newCachedThreadPool();//创建一个根据需要可随时创建新线程的线程池,当已经创建的线程中有可用的时便重用
		Executors.newSingleThreadExecutor();//创建一个使用单个线程的线程池,并以无界队列方式运行
		//调用方法提交线程任务并执行
		Runnable task=new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
				
			}
		};
		executors.execute(task);
	}
}

注:Runnable与Callable对象的提交执行方式不同,Runnable对象调用execute方法,而Callable对象调用submit方法。

 

 

 

欢迎各位指出错误以及不足,谢谢

相关文章
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
45 1
C++ 多线程之初识多线程
|
28天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
19 3
|
28天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
17 2
|
28天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
29 2
|
28天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
33 1
|
28天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
35 1
|
28天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
25 1
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
1月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
47 6
|
1月前
|
存储 运维 NoSQL
Redis为什么最开始被设计成单线程而不是多线程
总之,Redis采用单线程设计是基于对系统特性的深刻洞察和权衡的结果。这种设计不仅保持了Redis的高性能,还确保了其代码的简洁性、可维护性以及部署的便捷性,使之成为众多应用场景下的首选数据存储解决方案。
41 1