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花费在上下文的切换的时间将多于运行程序的时间!

时间: 2024-09-28 21:03:11

Java多线程编程— 概念以及经常使用控制的相关文章

拨开云雾见天日 —— Java多线程编程概念剖析

说到Java多线程编程,大多数人都会想到继承Thread或实现Runnable编程,new 一个Thread实例,调用start()方法,由OS调用即可.具体过程如下: public class MyThread extends Thread {     @Override     public void run() {         System.out.println("MyThread");     }     public static void main(String[] 

Java多线程编程— 概念以及常用控制

多线程能满足程序员编写非常有效率的程序来达到充分利用CPU的目的,因为CPU的空闲时间能够保持在最低限度.有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程.线程的运行中需要使用计算机的内存资源和CPU. 一.    进程与线程的概念 这两者的概念,这里只给出自己狭隘的理解: 进程:进程是一个独立的活动的实体,是系统资源分配的基本单元.它可以申请和拥有系统资源.每个进程都具有独立的代码和数据空间(进程上下文).进程的切换会有

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

一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过多线程的使用,可以编写出非常高效的程序.但如果创建了太多的线程,程序执行的效率反而会降低. 同时上下文的切换开销也很重要,如果创建太多的线程,CPU花费在上下文的切换时间将对于执行程序的时间. 二.Java多线程编程 概念 在学习多线程时,我们应该首先明白另外一个概念. 进程:是计算机中的程序关于某

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

Java多线程编程总结一 – 初识多线程 进程.多进程.线程.多线程的概念 进程(process):CPU的执行路径.通俗的说就是系统中正在运行的程序.比如我们打开了浏览器.QQ等等,这些程序一旦被打开运行了,就是所谓的进程. 多进程:系统中同时运行的多个程序.这个我们应该不难理解了,在打开浏览器的同时我们也可以QQ聊天.CS单机游戏等. 线程(thread):运行在进程中的运行单元.比如迅雷下载中我们的某一个下载任务就是一个线程. 多线程:同理可知,每个进程里面有多个独立的或者相互有协作关系的

Java多线程编程基础之线程对象

在进入java平台的线程对象之前,基于基础篇(一)的一些问题,我先插入两个基本概念. [线程的并发与并行] 在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制有多种形式(大多数是时间片轮巡为主),但无论如何,要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent).而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行的方式叫做并行(parallel). 在上面包括以后的所有论述中,请各位朋友谅解,我无法用最准确的词语来定义储

Java多线程编程详解

线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synch

Java - 32 Java 多线程编程

Java 多线程编程 Java给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 多线程是多任务的一种特别的形式.多线程比多任务需要更小的开销. 这里定义和线程相关的另一个术语:进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程.一个线程不能独立的存在,它必须是进程的一部分.一个进程一直运行,直到所有的非守候线程都结束运行后才能结束. 多线程能满足程序员编写非常有效率的程序来达到充分利用CP

汪大神Java多线程编程实战

课程目录:├─1│  ├─Java并发编程.png│  ├─源码+ppt.rar│  ├─高并发编程第一阶段01讲.课程大纲及主要内容介绍.wmv│  ├─高并发编程第一阶段02讲.简单介绍什么是线程.wmv│  ├─高并发编程第一阶段03讲.创建并启动线程.mp4│  ├─高并发编程第一阶段04讲.线程生命周期以及start方法源码剖析.mp4│  ├─高并发编程第一阶段05讲.采用多线程方式模拟银行排队叫号.mp4│  ├─高并发编程第一阶段06讲.用Runnable接口将线程的逻辑执行单元

《Java多线程编程核心技术》推荐

写这篇博客主要是给猿友们推荐一本书<Java多线程编程核心技术>. 之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象. 只要你有一点点Java基础,你就可以尝试去阅读它,相信定会收获甚大! 博主之前网上找了很久都没完整pdf电子版的,只有不全的试读版,这里博主提供免费.清晰.完整版供各位猿友下载: http://download.csdn.net/detail/u013142781/9452683 刚刚已经提到,<Java多线程编程核