轻松学会多线程(二)——多线程相关概念介绍

上一篇文章中,我们宏观介绍了多线程的背景,今天我们上一些干货。

在展开讲解多线程之前,我们需要明白进程与线程之间的关系。

进程与线程

一个关于进程和线程的比喻很贴切:一个进程就像是工厂的一个车间,代表CPU所能处理的单个任务,任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。而车间的工人,就好比线程,一个进程可以包含多个线程。

(线程,就好比工厂里的工人,车间的空间是工人们共享的,多个房间是每个工人都可以进出的)

操作系统中,所有运行的任务都对应一个进程。当一个程序进入内存运行,即变成一个进程。比如Hibernate中,一个Session就对应一个进程,用户发出的请求就对应一个进程。请求结束,进程结束。每个Session都有自己状态;多个用户请求,都会独立处理。所以进程就具有了独立性(拥有自己的独立资源,每个进程都有自己私有的地址空间)、动态性(区别于静态指令的程序,动态就会有状态)、并发性(并发执行,互不影响)。

而线程是进程的组成部分。线程拥有自己的堆栈、程序计数器和自己的局部变量,但它不拥系统资源。一个进程往往包含多个线程,这多个线程共享父进程的全部资源。

进程间不共享内存,而线程间共享内存很容易。线程在程序中第独立的,并发的执行流。线程共享内存、文件句柄和其他米格进程应有个状态。

创建线程

创建线程的方式有多种,可以直接继承Thread类,也可以实现Runnable接口实现多线程。我们可以直接new 一个Thread或者将一个Runnable传入Thread构造函数。等等。

//方法:直接new Thread
		Thread thread1 = new Thread() {
			@Override
			public void run() {
			}
		};
		thread1.start();

		//方法:将Runnable传入Thread构造函数
		Thread thread2 = new Thread(new Runnable() {
			@Override
			public void run() {
			}
		});
		thread2.start();

创建的方式有多种,看你的喜好使用。我喜欢使用实现Runnable接口的方式创建。因为这种方式有很多好处:

1、将线程创建与业务逻辑分来,更加面向对象;

2、Java不支持多继承,如果采用继承Thread类的方式,则不能再继承其他父类。

3、可以多个线程共享一个target对象。也就是说,这种方式,非常适合多个相同的线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,体现面向对象思想。

多线程的问题

在面向服务架构中,我们使用ESB技术,来完成系统间交互,致力于解决信息孤岛问题;在面向对象编程中,我们要面向抽象编程,要对公共特征的属性进行抽象。则否,面向对象的程度不够,系统就更加无法适应变化。

而在使用多线程时,多个线程之间是共享进程内数据的。

如果各个线程只是从共享数据中读取数据,则比较容易实现数据共享。例如,我提供一个高考成绩查询的接口,每一次查询请求都会启动一个线程,多个线程共享高考成绩的数据;

然而,实际情况中,很多时候都需要多个线程共同维护一份共享数据。例如,缓存框架,它是以维护一份公共缓存为基础,当多个对象取缓存时,需要进行同步处理;或者说多个线程,需要控制器执行顺序,这是也需要使用锁或者同步机制。

也就是说,线程的执行是竞相的,我们需要使用一定的机制,控制其并发。

拿下面一个卖票的例子来举例(此实例来自海涛博客):

现在一共三个窗口,共有20张票。首先,我们先不对三个窗口进行控制。三个窗口同时卖票:

package com.lzq.thread;

public class Test3 implements Runnable {
	private Integer ticket = 20;
	public void run() {
		System.out.println(Thread.currentThread().getName() + ": 开始卖票!");
		while (ticket > 0) {
			try {
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ":卖掉 " + ticket--
					+ " 号票 ");
		}
	}
	public static void main(String[] args) {
		Test3 test = new Test3();
		Thread t1 = new Thread(test, "1号窗口");
		Thread t2 = new Thread(test, "2号窗口");
		Thread t3 = new Thread(test, "3号窗口");
		t1.start();
		t2.start();
		t3.start();
	}
}

运行结果最后会出现:

我们明明限定了while(ticked>0)的情况,可是当卖完最后一张票后,还是卖了第“0”张票和第“-1”张票,这是由于当只剩下最后一张票时,三个窗口(即三个进程)都满足ticked>0的条件,就进入到了while循环里面,然后就卖了三张票:第“1”张票、第“0”张票和第“-1”张票。

这种情况的好处就是:同一时刻,三个窗口能够同时售票,能够实现快速售票;然而,这种方式存在数据同步问题。

下面,我们采用Java中的同步机制,解决上面的同步问题。

public class Test3 implements Runnable {
	private static int ticketCount = 10;
	public void run() {
		Thread currentThread = Thread.currentThread();
		System.out.println(currentThread.getName() + ": 开始卖票!");
		while (true) {
			synchronized ("2") {//采用同步机制
				if (ticketCount > 0) {
					try {
						currentThread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + ":卖掉 "
							+ ticketCount-- + " 号票 ");
				}
			}
		}
	}
}

结果如图所示:

而这时候采用同步机制,每个线程近来的时候,都会加上把锁,然后再判断ticketCount是否大于零。一旦有线程拿到了锁,则其他线程则只能在外等待,无法进入。等拿到锁的对象完成操作,释放锁对象之后,其他线程才能进入。依次类推。

所以这种处理方式能够保证程序的正确性,不出现售出第“0”张票、第“-1”张票的情况。但是同一时刻,只能有一个线程拿到锁。执行速度比较缓慢。

使用synchronized关键字,只是处理多线程的一种方式,Java的JDK中还提供了重入锁、读写锁、Condition对象、Semaphore信号量以及ThreadLocal线程局部变量等等并发控制方法。后续文章中会陆续介绍。

以我对多线程的了解,大家还是要多看一些底层的东西,不使用那些工具,直接使用Runnable接口和Thread来进行线程控制。使用多了,JDK中提供的各种多线程的工具一看也就会用了。在多线程编程中,最重要的并不是怎样使用多线程编程,而是要明白什么时候需要使用多线程的问题。

而这一步,却需要我们不断的积累,才能够做到。光凭借看书、学习是远远不够的。

本篇文章,阐述了线程与进程之间的关系,介绍了多线程的创建方式,以及我推荐大家的方式及理由。最后由介绍了多线程的使用中遇到的问题,如何更好的使用多线程,提供了思路。谢谢关注。

时间: 2024-11-18 12:19:19

轻松学会多线程(二)——多线程相关概念介绍的相关文章

Java多线程(二) 多线程的锁机制

当两条线程同时访问一个类的时候,可能会带来一些问题.并发线程重入可能会带来内存泄漏.程序不可控等等.不管是线程间的通讯还是线程共享数据都需要使用Java的锁机制控制并发代码产生的问题.本篇总结主要著名Java的锁机制,阐述多线程下如何使用锁机制进行并发线程沟通. 1.并发下的程序异常 先看下下面两个代码,查看异常内容. 异常1:单例模式 1 package com.scl.thread; 2 3 public class SingletonException 4 { 5 public stati

WebService学习总结(二)——WebService相关概念介绍

一.WebService是什么? 1. 基于Web的服务:服务器端整出一些资源让客户端应用访问(获取数据) 2. 一个跨语言.跨平台的规范(抽象) 3. 多个跨平台.跨语言的应用间通信整合的方案(实际) 二.为什么要用Web service? web service能解决: 跨平台调用 跨语言调用 远程调用 三.什么时候使用web Service? 1. 同一家公司的新旧应用之间 2. 不同公司的应用之间 3. 一些提供数据的内容聚合应用:天气预报.股票行情 四.Web Service中的几个重

【python标准库学习】thread,threading(二)多线程同步

继上一篇介绍了python的多线程和基本用法.也说到了python中多线程中的同步锁,这篇就来看看python中的多线程同步问题. 有时候很多个线程同时对一个资源进行修改,这个时候就容易发生错误,看看这个最简单的程序: import thread, time count = 0 def addCount(): global count for i in range(100000): count += 1 for i in range(10): thread.start_new_thread(ad

iOS开发多线程篇—多线程简单介绍

iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcode,系统就会分别启动2个进程 通过“活动监视器”可以查看Mac系统中所开启的进程 2.什么是线程 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行 比如使用酷狗播放音乐.使用迅雷下载电影,都需要在线程中执行 3.线程

iOS开发多线程篇—多线程的的相关概念(1)

iOS开发多线程篇-多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcode,系统就会分别启动2个进程 通过"活动监视器"可以查看Mac系统中所开启的进程 2.什么是线程 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行 比如使用酷狗播放音乐.使用迅雷下载电影,都需要在线程中执行

C#多线程之旅(1)——介绍和基本概念

原文目录C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅(4)——同步本质 ...... C#多线程之旅(1)——介绍和基本概念 一.多线程介绍 C#通过多线程支持并行执行的代码.一个线程是一个独立执行的路径,可以同时与其他线程一起运行.一个C#客户端程序(Console,WPF,Winows Forms)开始于一个单独的线程,该线程由CLR和操作系统自动地

iOS开发多线程篇—NSOperation简单介绍

iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作?:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: (1)先将需要执行的操作封装到一个NSOperation对象中 (2)然后将NSOperation对象添加到NSOperationQueue中 (3)系统会?动将NSOperationQueue中的NSOpe

[.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 多线程高级应用

[.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 多线程高级应用 本节要点: 上节介绍了多线程的基本使用方法和基本应用示例,本节深入介绍.NET多线程中的高级应用. 主要有在线程资源共享中的线程安全和线程冲突的解决方案:多线程同步,使用线程锁和线程通知实现线程同步. 1. ThreadStatic特性 特性:[ThreadStatic] 功能:指定静态字段在不同线程中拥有不同的值 在此之前,我们先看一个多线程的示例: 我们定义一个静态字段: static

iOS中多线程原理与runloop介绍

http://mobile.51cto.com/iphone-403490.htm iOS中多线程原理与runloop介绍 iPhone中的线程应用并不是无节制的,官方给出的资料显示iPhone OS下的主线程的堆栈大小是1M,第二个线程开始都是512KB.并且该值不能通过编译器开关或线程API函数来更改.只有主线程有直接修改UI的能力.……>>详细 兄弟专题:iOS人机交互指南之UI设计基础 1 iOS多线程编程知多少 在iOS的世界里有两种实现多线程的方式: 多线程是一个比较轻量级的方法来

OS开发多线程篇—NSOperation简单介绍

iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作?:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: (1)先将需要执行的操作封装到一个NSOperation对象中 (2)然后将NSOperation对象添加到NSOperationQueue中 (3)系统会?动将NSOperationQueue中的NSOpe