JAVA之多线程的创建
转载请注明源出处:http://www.cnblogs.com/lighten/p/5967853.html
1.概念
老调重弹,学习线程的时候总会牵扯到进程的概念,会对二者做一个区分。网上有较多的解释,这里引入一个感觉很专业的解释(摘自百度经验):
1)进程是具有独立功能的程序对于某个数据集合的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
2)线程是进程的一个实体,是CPU调度和分派的一个基本单位,它是比进程更小的能独立运行的基本单位。线程基本自己不拥有系统资源,只拥有一点在运行中必不可少的资源(比如程序计数器,一组寄存器和栈),但是它可以与同属同一个进程的其他的线程共享进程所拥有的全部资源。
进程与线程的区别在于以下几个方面:
1)地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程中的线程对于其他进程而言是不可见的。
2)通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要同步和互斥的手段辅助,以保证数据的一致性。
3)调度和切换:线程上下文切换比进程上下文切换快的多。
4)在多线程OS中,进程不是一个可执行的实体。
以上的概念有些繁琐不好理解,当然还是很有必要的,这里我个人想到个例子方便理解:
程序执行无非就是要使用CPU等硬件资源,以单核CPU为例,就好比是一个篮球场。多个进程就好比有多个篮球俱乐部,操作系统就是篮球场管理人员,他来协调哪个俱乐部什么时候使用篮球场。俱乐部之间都有属于自己内部的秘密,与其他俱乐部交流的手段有限,但内部的秘密自己人可以很方便的获得信息。一个俱乐部有多个球队,一队,二队等,这就是多个线程了。一队上场锻炼的时候,二队就歇着呗,一队打累了,打完了或者被二队抢场子了,就二队使用篮球场了。JVM(java虚拟机)俱乐部的领导不干了,一队是主力啊,要更多的训练时间啊,但又不好明着伤二队的心,反正是争抢场子,就掷色子吧,不过1-4的时候一队上,5、6就二队上(线程优先级的概念,可能举的例子不恰当),但是领导说了不算啊,这里是操作系统,篮球管理员的地盘,我的地盘我做主,要看管理员认不认可这个规则了(注意,线程优先级要看具体的操作系统,不是100%有效)。那咋办呢,领导不想各队混乱的抢占资源,就派了一个催眠师,让一些队睡觉(wait或sleep 二者有区别,这里不介绍),需要他们的时候再叫醒他们(notify),叫醒所有被催眠的队伍就(notifyAll),万幸的是这种方法被管理员认可了(笑)。
以上就是一些基本的理解了,对于更详细的细节差异,比如wait和sleep,同步的作用等等,之后介绍到的话会继续使用这个例子介绍。
2.Java创建线程的方法
Java最原始的创建线程的方法只有两种,一种是继承Thread类,另一种是实现Runnable接口。网上可能会说有三种,多出来的一种是通过Excutors创建线程池pool,然后提交一个实现了Callable接口的类给pool,让pool执行,返回一个Future对象。但是实际上这种方式并不能说是一种新的方法,只能说是一种新的思路罢了,因为其内部还是使用的第二种方式,具体代码如下:
// Excutors使用演示 MyCallable是我写的一个实现了Callable接口类
ExecutorService pool = Executors.newFixedThreadPool(1);
Callable c = new MyCallable("name为" + i);
Future f = pool.submit(c); // Future中保存了Callable接口需实现的方法的返回值 // 这里具体看看pool.submit(c)中做了什么
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
} // 上面可以看出Callable的涵义就是一个执行的任务
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
} // newTaskFor(Callable)返回的RunnableFuture接口很明显的看出是使用的Runnable方法
// newTaskFor方法实际上是创建了一个FutureTask对象,其实现了RunnableFuture接口,下面是其run方法的实现
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
} //execute(ftask)的实现
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
所以说JAVA创建一个线程最原始的方法就是那两个,其它的都是扩展而来的。实际上执行还是Thread类,接口又不能执行,多出一个Runnable接口也就是因为Java的语法限制,单继承和多实现(针对于类,接口可以多继承)。如果都继承Thread类,那就意味着这个类不能继承其它的类了,这显然是不好的。
1)继承Thread类,覆写run方法。
public class A extends Thread{ @Override
public void run() {
System.out.println("线程启动了");
} public static void main(String[] args) {
new A().start();
}
}
2)实现Runnable方法,实现run方法。
public class B implements Runnable { @Override
public void run() {
System.out.println("runnable is start");
} public static void main(String[] args) {
// 这里可以看出还是使用的Thread类来运行的
new Thread(new B()).start();
}
}
3 小结
Java对多线程开发提供了强大的原生类,都在java.util.concurrent下。多线程的开发确实有些难点,比如思考难以全面,潜在问题难以检测,出现的问题难以重现等等。但是还是有方法去处理的,这章主要就是对线程的基础概念和Java线程的创建做一个简答的介绍,万丈高楼平地起,基础扎实了,其它问题处理起来就会得心应手了。
JAVA之多线程的创建的更多相关文章
- java学习多线程之创建多线程一
现在我们有这么一个需求,就是在主线程在运行的同时,我们想做其他的任务,这个时候我们就用到了多线程.那么如何创建多线程,我们知道在系统当中qq的多线程创建是由操作系统来完成的,那么如果我们想在java当 ...
- java中多线程 - 如何创建多线程
线程 什么是线程: 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源 表面上 ...
- Java进阶(四十二)Java中多线程使用匿名内部类的方式进行创建3种方式
Java中多线程使用匿名内部类的方式进行创建3种方式 package cn.edu.ujn.demo; // 匿名内部类的格式: public class ThreadDemo { public st ...
- Java多线程(1) 创建
一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下以下这张较为经典的图: Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Threa ...
- 牛客网Java刷题知识点之什么是进程、什么是线程、什么是多线程、多线程的好处和弊端、多线程的创建方式、JVM中的多线程解析、多线程运行图解
不多说,直接上干货! 什么是进程? 正在进行中的程序(直译). 什么是线程? 就是进程中一个负责程序执行的控制单元(执行路径). 见 牛客网Java刷题知识点之进程和线程的区别 什么是多线程? 一个进 ...
- java多线程-概念&创建启动&中断&守护线程&优先级&线程状态(多线程编程之一)
今天开始就来总结一下Java多线程的基础知识点,下面是本篇的主要内容(大部分知识点参考java核心技术卷1): 1.什么是线程以及多线程与进程的区别 2.多线程的创建与启动 3.中断线程和守护线程以及 ...
- Java之多线程创建方式
多线程的由来 我们在之前,学习的程序在没有跳转语句的前提下,都是由上至下依次执行,那现在想要设计一个程序,边打游戏边听歌,怎么设计?要解决上述问题,咱们得使用多进程或者多线程来解决. 多线程的好处: ...
- Java多线程的创建(二)
前言: 虽然java的API中说创建多线程的方式只有两种(There are two ways to create a new thread of execution),分别是继承Thread类创建和 ...
- Java:多线程概述与创建方式
目录 Java:多线程概述与创建方式 进程和线程 并发与并行 多线程的优势 线程的创建和启动 继承Thread类 start()和run() 实现Runnable接口 实现Callable接口 创建方 ...
随机推荐
- gerrit 使用笔记
添加git hooks git库的钩子目录中有一个commit-msg脚本文件,可以在git执行commit时,在提交信息中自动添加一个唯一的Change-Id scp -P 29419 admin@ ...
- ios8消息快捷处理——暂无输入框
if (isiOS8) { //ios8的远程推送注册 NSSet *set = nil; #if 1 //1.创建消息上面要添加的动作(按钮的形式显示出来) UIMutableUserNotific ...
- Windows下Nginx的启动、停止等命令(转)
Windows下Nginx的启动.停止等命令 在Windows下使用Nginx,我们需要掌握一些基本的操作命令,比如:启动.停止Nginx服务,重新载入Nginx等,下面我就进行一些简单的介绍.1.启 ...
- wap资费页面
移动网关 CMWAP 返回vnd.wap.wml 用CMWAP接入点发一个http的请求时,移动的10.0.0.172这个代理网关会回一个确认页面,中国特色.处理的办法是检测到Content-type ...
- MySQL数据库优化技术之SQL语句慢查询定位
通过show status命令了解各种SQL的执行频率 MySQL客户端连接成功后,通过使用show [session|global] status 命令可以提供服务器状态信息: 其中的session ...
- Windows下cwRsync搭建步骤
文章(一) CwRsync是基于cygwin平台的rsync软件包,支持windows对windows.windows对Linux.Linux对windows高效文件同步.由于CwRsync已经集成了 ...
- C语言sizeof陷阱
执行以下程序,查看输出: #include <stdio.h> #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) int ...
- canvas-7globleCompositeOperation2.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 【Unity Shaders】学习笔记——SurfaceShader(八)生成立方图
[Unity Shaders]学习笔记——SurfaceShader(八)生成立方图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5630261.html ...
- delphi调用web service出现 Unable to retrieve the URL endpoint for Service/Port .....
delphi调用web service出现 Unable to retrieve the URL endpoint for Service/Port, 错误截图如下 查了很长时间, 发现在DataM ...