一、线程和多进程简介

1、多进程的概念

  • 当前的操作系统都是多任务OS
  • 每个独立执行的任务就是一个进程
  • OS将时间划分为多个时间片(时间很短)
  • 每个时间片内将CPU分配给某一任务,时间片结束,CPU将自动回收,再分配给另外任务。从外部看,所有的任务是同时执行。但是在CPU上,任务是按照串行依次运行(单核CPU)。如果是多核CPU,多个进程任务可以并行。但是在单核上,多进程只能串行执行。
  • 多进程的优点:
  • 可以同时运行多个任务
  • 程序因I/O堵塞时,可以释放CPU,让CPU为其他程序服务
  • 当系统有多个CPU时,可以为多个程序同时服务
  • 我们使用的CPU不在提高频率,而是提高核数
  • 2005年Herb Sutter的文章The free lunch is over,指明多核和并发程序才是提高程序性能的唯一办法。
  • 串行程序,是指程序只能在单核上运行,无法利用多个CPU;
  • 并行程序,是指程序可以利用多个计算核运行,加快计算速度。
  • 多进程的缺点
  • 太笨重,不好管理
  • 不好切换

2、多线程概念

  • 一个程序可以包括多个子任务,可串行/并行
  • 每个子任务可以成为一个线程
  • 如果一个子任务堵塞,程序可以将CPU调度到另外一个子任务进行工作。这样CPU还是保存在本程序中,而不是被调度到别的程序(进程)去。这样,提高本程序所获得CPU时间的和利用率。

3、多进程vs多线程

  • 线程共享数据
  • 线程通讯更高效
  • 线程更轻量级,更容易切换
  • 多个线程更容易管理

多进程示列程序

public class ProcessDemo1 {

	public static void main(String[] args) {
		while(true)
		{
			int a = (int) (Math.random() * 100);
			System.out.println(" main thread is running " + a);
			try {
				Thread.sleep(5000); //5000毫秒
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}		
	}
}

sleep函数目的是让当前的程序睡眠5000毫秒

java 多进程写文件 java如何多进程_多线程

从输出结果来看,有两控制台。这里右键->run了两次,所以有两个Java程序运行(两个Java.exe在运行)。它们分别有各自的运行空间和输出位置,两个Java程序运行是互不干扰的,相互之间通讯也很困难。多进程实际上是多个Java程序在运行

注: Eclipse里面关闭程序,一定要把所有的console窗口都关闭,防止有进程还在运行

多线程示列程序

public class ThreadDemo1
{
	public static void main(String args[]) throws Exception
	{
		new TestThread1().start();
		while(true)
		{
			System.out.println("main thread is running");
			Thread.sleep(1000);
		}
	}
}

class TestThread1 extends Thread
{
	public void run() 
	{
		while(true)
		{
			System.out.println(" TestThread1 is running");
			try {
				Thread.sleep(1000); //1000毫秒=1s
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

java 多进程写文件 java如何多进程_System_02


从运行结果可以看到main thread和test thread1交替出现,而且是无规律的出现,有可能一个出现一次另外一个出现两次,本程序只有一个Java.exe在运行。这里说明,程序不一定要执行完第一行才能执行第二行。程序不在固守上一行到下一行顺序执行,可以两段代码独立的运行。

二、多线程实现

Java多线程创建的两种方法

1.java.lang.Thread
Thread方法

  • 通过继承Thread类创建线程,通过start方法启动线程的run方法
public class Thread1 extends Thread{
	public void run()
	{
		System.out.println("hello");
	}
	public static void main(String[] a)
	{
		new Thread1().start();
	}
}

2、java.lang.Runnable接口
Runnable方式

  • 通过实现Runnable接口创建线程
  • 实现Runnable的对象必须包装在Thread类里面,才可以启动
  • 通过start方法启动线程的run方法
public class Thread2 implements Runnable{
	public void run()
	{
		System.out.println("hello");
	}
	public static void main(String[] a)
	{
		new Thread(new Thread2()).start();
	}
}
  • Runnable接口是Java的四大接口之一
  • Java主要的四个接口
  • Clonable,用于对象克隆
  • Comparable,用于对象比较
  • Serializable,用于对象序列化
  • Runnable,用于对象线程化

Java多线程启动

1、启动

  • start启动方法,会自动以新进程调用run方法
  • 直接调用run方法,将变成串行执行
  • 同一线程,多次start会报错,只执行第一次start方法
  • 多个线程启动,其启动的先后顺序是随机的
  • 线程无需关闭,只要其run方法执行结束后自动关闭
  • main函数(线程)可能早于新线程结束,整个查询并不终止
  • 整个程序终止是等所有的线程都终止(包括main函数线程)

2、多线程的运行规则
规则一

  • 若调用run方法,来启动run方法,将会是串行运行
public class ThreadDemo0
{
	public static void main(String args[]) throws Exception
	{
		new TestThread0().run();
		while(true)
		{
			System.out.println("main thread is running");
			Thread.sleep(10);
		}
	}
}
 class TestThread0  	
{
	public void run() 
	{
		while(true)
		{
			System.out.println(" TestThread1 is running");
			try {
				Thread.sleep(1000); //1000毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

java 多进程写文件 java如何多进程_java 多进程写文件_03


程序一直输出 TestThread1 is running,而没有输出main thread is running说明程序是串行执行,new TestThread0().run();语句还没运行完。

  • 若调用start方法,来启动run方法,将会是并行运行(多线程运行)

new TestThread0().run();

修改为

new TestThread1().start();

java 多进程写文件 java如何多进程_Java_04


两个线程交替运行

规则二:

  1. main线程可能早于子线程结束
  2. main线程和子线程都结束,整个程序才算终止
public class ThreadDemo2
{
	public static void main(String args[]) throws InterruptedException
	{
		new TestThread2().start();
//		while(true)
//		{
//			System.out.println("main thread is running");
//			Thread.sleep(1000);
//		}
	}
}
 class TestThread2 extends Thread
{
	public void run() 
	{
		while(true)
		{
			System.out.println("TestThread2" + 
			" is running");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

把这段代码注释了

//		while(true)
//		{
//			System.out.println("main thread is running");
//			Thread.sleep(1000);
//		}

在执行new TestThread2().start()语句后;main函数(main线程)就结束了,而子线程还在运行。说明主线程可以早于子线程结束

规则三:

  1. 实现Runnable的对象必须包装在Thread类里面,才可以启动
  2. 不能直接对Runnable的对象进行start方法。
public class ThreadDemo3
{
	public static void main(String args[])
	{
		//new TestThread3().start();
		//Runnable对象必须放在一个Thread类中才能运行
		TestThread3 tt= new TestThread3();//创建TestThread类的一个实例
		Thread t= new Thread(tt);//创建一个Thread类的实例
		t.start();//使线程进入Runnable状态
		while(true)
		{
			System.out.println("main thread is running");
			try {
				Thread.sleep(1000); //1000毫秒
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
class TestThread3 implements Runnable //extends Thread
{
	//线程的代码段,当执行start()时,线程从此出开始执行
	public void run()
	{
		while(true)
		{
			System.out.println(Thread.currentThread().getName() +
			" is running");
			try {
				Thread.sleep(1000); //1000毫秒
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
System.out.println(Thread.currentThread().getName() +
			" is running");

该方法获取并输出当前线程的名称。JVM会自动给每个子线程自动派发一个名字。这里线程名为Thread-0。

java 多进程写文件 java如何多进程_多线程_05

规则四:

  1. 一个线程对象不能多次start,多次start会报出异常。
TestThread4 t=new TestThread4();
		t.start();
		t.start();
		t.start();

java 多进程写文件 java如何多进程_System_06

  1. 多个线程都start后,先执行哪一个,完全有JVM/OS来主导,程序员无法指定。

两种多线程实现方法对比
Thread vs Runnable

  1. Thread占据了父类的名额(使继承自Thread类的类不能再继承于其他类),不如Runnable方便
  2. Thread类实现Runnable
  3. Runnable启动时需要Thread类的支持
  4. Runnable更容易实现多线程中资源共享

结论: 建议实现Runnable接口来完成多线程