Java多线程编程— 概念以及经常使用控制
多线程能满足程序猿编写很有效率的程序来达到充分利用CPU的目的,由于CPU的空暇时间可以保持在最低限度。有效利用多线程的关键是理解程序是并发运行而不是串行运行的。比如:程序中有两个子系统须要并发运行,这时候就须要利用多线程编程。
线程的运行中须要使用计算机的内存资源和CPU。
一、 进程与线程的概念
这两者的概念,这里仅仅给出自己狭隘的理解:
进程:进程是一个独立的活动的实体,是系统资源分配的基本单元。
它能够申请和拥有系统资源。
每一个进程都具有独立的代码和数据空间(进程上下文)。
进程的切换会有较大的开销。
进程,是一个“执行中的程序”。
程序是一个静态的没有生命的实体,仅仅有处理器赋予程序生命时(操作系统执行之),它才干成为一个活动的实体。我们称其为进程。
也就是说。进程是正在执行的程序的实例(an instance of a computer program that is being executed)。比如,你执行一个qq。就会启动一个进程,再次执行qq。就会再启动一个进程。
线程: 事实上,60年代,进程不仅是资源分配的基本单元。还是资源调度的基本单元。然而随着计算机技术的发展,进程出现了非常多弊端,一是因为进程是资源拥有者。创建、撤消与切换存在较大的时空开销,因此须要引入轻型进程。二是因为对称多处理机(SMP)出现,能够满足多个执行单位,而多个进程并行开销过大。
因此在80年代,出现了能独立执行的基本单位——线程(Threads)。
也就是说,如今。线程才是资源(cpu)调度的基本单元,它是一个程序内部的控制流程。线程是进程内部的更小的单元。它基本不占用系统资源。一个进程内的多个线程是为了协同工作来处理一件事情。
简单总结来说就是。进程是为了分配得到资源,然后由它里面的线程利用资源来处理事情。
进程是一个壳子,实际干事的都是线程。
(比如,我们的main函数作为主线程)。
二者较为深入一点的总结:http://wangzhipeng0713.blog.163.com/blog/static/1944751652015522359459/
二、 线程的创建和启动
2.1 方式一:线程类实现Runnable接口
定义线程类:
/**
* 定义线程类(实现Runnable接口)
*
* @author wangzhipeng
*
*/
public class Runner1 implements Runnable { @Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("New Thread Runner1-->" + i);
}
}
}
測试类:
public class TestThread1 {
// 1、main方法为主线程
public static void main(String[] args) {
// 2、启动第二个线程
Runner1 runner1 = new Runner1();
Thread thread = new Thread(runner1, "zhipeng");// 注意,Runner类实现了Runnable接口,启动线程时须要用一个Thread类将其包起来
thread.start();// 调用start方法。使得线程进入“就绪”状态 for (int i = 0; i < 100; i++) {
System.out.println("【Main】 Thread-->" + i);
}
}
}
执行结果:
2.2 方式二:线程类继承Thread类并重写其run方法
定义线程类:
/**
* 定义线程类(继承Thread类)
*
* @author wangzhipeng
*
*/
public class Runner2 extends Thread { @Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("New Thread Runner1-->" + i);
}
}
}
測试类:
public class TestThread2 { // main方法为主线程
public static void main(String[] args) {
// 1、线程类继承Thread类的start写法
Runner2 runner2 = new Runner2();
runner2.start();// 这里须要注意:由于Runner2已经是一个线程类了,所以不须要再对它进行包装,直接调用start就可以 // 2、线程类实现Runnable接口的start写法(须要用Thread类包装)
// Thread thread = new Thread(runner1);
// thread.start(); for (int i = 0; i < 100; i++) {
System.out.println("【Main】 Thread-->" + i);
}
} }
执行结果:
2.3 小结
尽管两种方式都能达到同样的效果,但我们一般不採用继承的方式实现多线程。由于一旦继承了Thread类,你的类就无法再继承其他的类。而实现了Runnable接口后。你还能够实现其他接口或继承其他类。也就是说面向接口编程比較灵活。
三、 线程的状态转换
这里须要注意的是,线程调用start()方法后,是进入“就绪状态”,而不是“执行状态”。
也就是说,是线程告诉操作系统,我已准被调度所须要的一切事物,仅仅有在被调度后线程才进入到执行状态。
四、 线程控制的基本方法
这里主要简介sleep/join/yield/以及线程的优先级。至于wait与notify/notifyAll这一对重要的方法会在后面一篇文章。线程同步问题中具体介绍。
4.1 sleep方法
非常easy非经常常使用,是Thread类的静态方法:
演示样例程序
线程类:
import java.util.Date; /**
* 通过继承Thread类实现线程类
*
* @author wangzhipeng
*
*/
public class MyThread extends Thread {
public void run() {
/**
* 每一秒钟输出一下当前日期
*/
while (true) {
System.out.println("---->" + new Date());
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
Sleep測试类:
public class TestInterrupt {
public static void main(String[] argStrings) {
MyThread myThread = new MyThread();
myThread.start();// 启动第二个线程
try {
Thread.sleep(5000);// 主线程5秒钟后终止第二个线程
myThread.interrupt();// 一般不用这样的方式终止线程--比較粗暴
// myThread.stop();//更加不用--更加粗暴
} catch (InterruptedException e) {
return;
}
}
}
这里须要注意“终止线程”的方式,上面提到了interrupt()与stop()两种方式都是比較粗暴的方式,即强行终止,一般不採用。
而是在线程类中定义一个信号量。然后client通过给该信号量赋值来“温柔”地控制线程的终止。比如给以下的线程类中的flag赋值false就可以终止线程。
public class MyThread extends Thread {
boolean flag = true;// 定义信号量来控制线程的终止 public void run() {
/**
* 每一秒钟输出一下当前日期
*/
while (flag) {
System.out.println("---->" + new Date());
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
4.2 join方法
join()代表将第二线程合并到主线程,也就是将第二线程与主线程顺序运行,而不是并发运行。
join(5000) 代表前5秒钟将第二线程合并到主线程,5秒过后。第二线程与主线程并发运行。
演示样例程序
线程类:
/**
* 定义线程类(继承Thread类)
*
* @author wangzhipeng
*
*/
public class Mythread2 extends Thread {
Mythread2(String s) {
super(s);
} /**
* 每一秒钟输出一下当前线程的名称
*/
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("I am " + getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
} }
}
join方法測试类:
/**
* join方法測试
*
* @author wangzhipeng
*
*/
public class TestJoin { public static void main(String[] args) {
Mythread2 mythread2 = new Mythread2("zhpeng");
mythread2.start();// 启动第二线程
try {
mythread2.join();// 将第二线程合并到主线程,也就是将第二线程与主线程顺序运行。而不是并发运行
// mythread2.join(5000);// 前5秒钟将第二线程合并到主线程,5秒过后。第二线程与主线程并发运行
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 主线程:循环输出一句话
*/
for (int i = 0; i < 10; i++) { System.out.println("I am Main Thread");
}
}
}
执行结果:
4.3 yield方法
Thread类的静态方法。
暂停当前正在运行的线程对象,并运行其它线程。也就是高风亮节。自己先暂停一下,让给别人先运行一下下。
演示样例代码
线程类:
/**
* 定义线程类(继承Thread类)
*
* @author wangzhipeng
*
*/
public class Mythread3 extends Thread {
public Mythread3(String s) {
super(s);
} public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + ": " + i);
// 假设i能被10整除。则让出cpu运行主线程,也就是说输出结果的子线程i为0、5、10、15等时,下一个输出必然为主线程的输出(仅仅要主线程没有运行完成)
if (i % 5 == 0) {
yield();
}
}
}
}
yield方法測试类:
/**
* yield方法測试类
*
* @author wangzhipeng
*
*/
public class TestYield {
public static void main(String[] argStrings) {
Mythread3 mythread3 = new Mythread3("------zhipeng");
mythread3.start();
// 主线程
for (int i = 0; i < 100; i++) {
System.out.println("-----MainThread " + i);
}
}
}
输出结果:
4.4 线程的优先级Priority
每个Java线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。Java优先级在MIN_PRIORITY(1)和MAX_PRIORITY(10)之间的范围内。默认情况下。每个线程都会分配一个优先级NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要。并且应该在低优先级的线程之前分配处理器时间。
然而,线程优先级不能保证线程运行的顺序,并且很依赖于平台。
演示样例程序
定义两个线程类:
public class T1 implements Runnable { @Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("----------T1");
}
} }
public class T2 implements Runnable { @Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("T2");
}
} }
測试类:
public class TestPriority { public static void main(String[] args) {
Thread thread1 = new Thread(new T1());
Thread thread2 = new Thread(new T2());
thread1.setPriority(Thread.NORM_PRIORITY + 5);// 给thread1线程的优先级加5。这样它被调度的机会就会比thread2大非常多
thread1.start();
thread2.start();
} }
执行结果:
五、 总结
进程是系统资源分配的基本单元,它是程序的执行演示样例,能够独立存在。线程是cpu调度的基本单元,是一个程序内部的控制流程,不能独立存在。必须依附于进程。一个进程包括多个线程,进程是为了得到系统资源,但实际上运作这些系统资源的都是线程。
通过对多线程的使用,能够编写出非常高效的程序。只是请注意,假设你创建太多的线程,程序运行的效率实际上是减少了。而不是提升了。由于,上下文的切换开销也非常重要。假设你创建了太多的线程,CPU花费在上下文的切换的时间将多于运行程序的时间!
Java多线程编程— 概念以及经常使用控制的更多相关文章
- Java多线程编程(学习笔记)
一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...
- Java多线程编程总结一:多线程基本概念
Java多线程编程总结一 – 初识多线程 进程.多进程.线程.多线程的概念 进程(process):CPU的执行路径.通俗的说就是系统中正在运行的程序.比如我们打开了浏览器.QQ等等,这些程序一旦被打 ...
- java多线程编程01---------基本概念
一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...
- Java多线程编程详解
转自:http://programming.iteye.com/blog/158568 线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Ja ...
- Java多线程编程总结(精华)
Java多线程编程总结 2007-05-17 11:21:59 标签:多线程 java 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http ...
- Java多线程编程核心技术
Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...
- Java - 32 Java 多线程编程
Java 多线程编程 Java给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 多线程是多任务的一种特别 ...
- java多线程编程模式
前言 区别于java设计模式,下面介绍的是在多线程场景下,如何设计出合理的思路. 不可变对象模式 场景 1. 对象的变化频率不高 每一次变化就是一次深拷贝,会影响cpu以及gc,如果频繁操作会影响性能 ...
- Java多线程编程实战指南(核心篇)读书笔记(三)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76686044冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
随机推荐
- 解决iOS空指针数据的问题
iOS开发中常常会遇到空指针的问题. 如从后台传回来的Json数据,程序中不做推断就直接赋值操作,非常有可能出现崩溃闪退. 为了解决空指针的问题,治标的方法就是遇到一个处理一个.这样业务代码里面就插了 ...
- Android Studio com.android.dex.DexException: Multiple dex files define(重复引用包)
如果你用Android Studio开发,并且要用其他项目作为library,这个问题是很容易出现的.出现这个问题的原因是包的重复引用,意思就是在你自己的项目中引用了某个包,而被你作为library的 ...
- HTTP请求报文、响应报文
HTTP请求报文 HTTP请求报文由3部分组成(请求行+请求头+请求体): 请求行:①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE.HEAD.OPTIONS.PUT. ...
- [python]bug和debug
bug:代码中存在的语法或者逻辑问题 debug:自查和解决代码中的问题 (coding五分钟,debug两小时) 一.出现bug原因的四大类型 1.粗心 1)错误案例 上面这个错误就是因为 if语句 ...
- windows CE项目开发
软件列表 1.Windows mobile 设备中心 2.Microsoft visual Studio 2008 3.串口调试工具(sscom42.exe) 4.Wince 6.0模拟器 5.vir ...
- VC++的函数指针和回调函数 及友元函数
什么是函数指针 函数指针是指向函数的指针变量.也就是说,它是一个指针变量,而且该指针指向一个函数. 对于指针变量来说,它的值是它指向的变量的地址.举个例子:指针变量pi是指向一个整型变量i的指针,则变 ...
- 【例题 7-6 UVA - 140】Bandwidth
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 暴力做就好. O(8!*26^2) [代码] /* 1.Shoud it use long long ? 2.Have you ev ...
- The Swift Programming Language 中文翻译版
原文(http://www.cnblogs.com/lkvt/p/3765349.html) 一.Welcome to Swift 1.关于Swift Swift是一种用于iOS和OS X应用的全新编 ...
- 怎么做好看的html5游戏界面
怎么做好看的html5游戏界面 一.总结 一句话总结:html5应该是完全可以做特别好看的游戏界面的.最下面那个背景图完全是一张图片动的雪和小动物可以是gif,或者是canvas,右边的那各个选择框就 ...
- amazeui学习笔记--css(常用组件9)--导航nav
amazeui学习笔记--css(常用组件9)--导航nav 一.总结 1.导航基本使用:<ul> 添加 .am-nav class 以后就是一个基本的垂直导航.默认样式中并没有限定导航的 ...