多线程能满足程序猿编写很有效率的程序来达到充分利用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多线程编程— 概念以及经常使用控制的更多相关文章

  1. Java多线程编程(学习笔记)

    一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...

  2. Java多线程编程总结一:多线程基本概念

    Java多线程编程总结一 – 初识多线程 进程.多进程.线程.多线程的概念 进程(process):CPU的执行路径.通俗的说就是系统中正在运行的程序.比如我们打开了浏览器.QQ等等,这些程序一旦被打 ...

  3. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  4. Java多线程编程详解

    转自:http://programming.iteye.com/blog/158568 线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Ja ...

  5. Java多线程编程总结(精华)

    Java多线程编程总结 2007-05-17 11:21:59 标签:多线程 java 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http ...

  6. Java多线程编程核心技术

    Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...

  7. Java - 32 Java 多线程编程

    Java 多线程编程 Java给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 多线程是多任务的一种特别 ...

  8. java多线程编程模式

    前言 区别于java设计模式,下面介绍的是在多线程场景下,如何设计出合理的思路. 不可变对象模式 场景 1. 对象的变化频率不高 每一次变化就是一次深拷贝,会影响cpu以及gc,如果频繁操作会影响性能 ...

  9. Java多线程编程实战指南(核心篇)读书笔记(三)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76686044冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...

随机推荐

  1. 洛谷 P1916 小书童——蚂蚁大战

    P1916 小书童——蚂蚁大战 题目背景 小A在你的帮助下,开始“刷题”,他在小书童里发现了一款叫“蚂蚁大战”(又称蛋糕保卫战)的游戏.(你懂得) 题目描述 游戏中会出现n只蚂蚁,分别有a1,a2…… ...

  2. Spring3拦截引发的问题——WEB开发中的client路径

    什么是client路径? 第一类.也就是html或js文件等client訪问的文件里的路径,这里包含一些资源文件的引入(js.css还有各种图片等),或是跳转到静态html页面,总之获取的都是静态资源 ...

  3. dot 语法全介绍

    0. 保存 保存为 pdf:dot -Tpdf iris.dot -o iris.pdf 1. 基本 (1)无向图.有向图.子图 graph G {} // 无向图 digraph G {} // 有 ...

  4. Log4j.properties 属性详解以及 LOG4J日志级别详解

    转自:https://blog.csdn.net/lovely0903jpp/article/details/82261607 假如项目的生产环境上增加请求以及响应信息的打印,这个时候,对于新手来说, ...

  5. what happens when changing the DOM via innerHTML

    what happens when changing the DOM via innerHTML

  6. C# 报表

    报表技术 1.OWC控件的使用 OWC是office web Components 是组件对象模型(COM)控件的集合,可用于将电子表格,图表和数据库发布到网站上. 在Office2003以后的版本中 ...

  7. Kaggle实战分类问题2

    Kaggle实战之二分类问题 0. 前言 1. MNIST 数据集 2. 二分类器 3. 效果评测 4. 多分类器与误差分析 5. Kaggle 实战 0. 前言 “尽管新技术新算法层出不穷,但是掌握 ...

  8. Day2:PYC

    一.pyc里装的是预编译后的字节码文件 二.一般存放在”__pycache__“目录 三.当python程序运行时,编译的结果是保存在位于内存中的PyCodeObject中,当Python程序运行结 ...

  9. 2015,我的投资理财策略(股权众筹+P2P网贷+活期理财)

    纸币流行,尤其是当今中国的市场经济,纸币几乎是一直是贬值的,每个人的财富都在被不断地稀释,可能是被政府.如果你不注意保值增值,你就越来越穷.     当年的万元户,在今天看来就是一个笑话,其实不怎么好 ...

  10. ehcache、memcache、redis三大缓存比较(转)

    最近项目组有用到这三个缓存,去各自的官方看了下,觉得还真的各有千秋!今天特意归纳下各个缓存的优缺点,仅供参考!  Ehcache 在Java项目广泛的使用.它是一个开源的.设计于提高在数据从RDBMS ...