java使用多线程


进程与线程

线程又称轻量级进程,是程序执行的最小单元,一个进程最少有一个线程,线程间通信比进程间通信更有优势,多个线程在一个进程中可以方便数据共享.注意线程的异常可能引起程序(进程)的崩溃.

线程虽然称轻量级进程,那只是对比进程来说,但开销还是很大的,要正确合理使用线程,一定要避免线程太多,造成线程上下文开销很大,从而影响程序的性能.

Windows系统多线程优于Unix/Linux,以多进程来说Unix/Linux比Windows有优势.
Java的跨平台是以针对不同平台(Windows/Linux/Macos)的虚拟机(JVM),屏蔽不同平台的差异.线程在JVM中没有直接实现而是调用不用平台的系统API创建的.Java中的一个线程对应了系统的一个线程.

线程的状态

  线程的状态分别为:新生→就绪→运行/等待→死亡,一般我们只考虑就绪/等待/运行,可以看看下图.

线程状态

如何使用系统API创建线程

在Windows系统使用系统API创建

#include <stdio.h>
#include <stdlib.h>

#include <Windows.h>  //CreateThread函数原型在Windows头文件

//回调函数
DWORD WINAPI  func(void* p)
{
	printf("func exec is ok!\n");
	return 0;
}//在Windows系统,创建线程要使用CreateThread
int main(int argc, char *argv[])
{
	//将func函数交给CreateThread API函数,创建完线程,执行func函数
	HANDLE thread = CreateThread(NULL,0,func,NULL,0,NULL);

	system("pause"); //暂停,比如新建的线程还没有执行,主线程已经运行结束,进程也就结束了
	CloseHandle(thread); 
	return 0;
}

在Linux系统使用API创建线程

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

//回调函数
void *func(void *args)
{
	printf("func exec is ok!\n");
}

//在Linux/unix中,使用pthread_create创建线程
int main(int argc, char *argv[])
{
	pthread_t pid;
	pthread_create(&pid, NULL, func, NULL);
	getchar();     //pause在Linux下不会阻塞等待,可以使用getchar或者fgetc
	return 0;
}

为什么要使用系统API创建线程呢?

熟悉不同平台的API,了解不同平台的差异,能够让我们知其所以然,知道了这些,就可以说Java的线程使用.

Java两种实现多线程的方式

1.继承Thread

public class MyThread extends Thread {

	public MyThread(String name) {
		setName(name);
	}

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}
}


/*
 * 多线程,要注意是执行是乱序的,当然也有可能是顺序的.
 * 1.让类继承Thread,重写run方法
 * 2.让类实现Runnable接口,重写run方法
 * 推荐使用使用Runnable接口,因为类只能单继承,而接口可以多实现
 */
public static void main(String[] args) {		
	System.out.println("main thread id:" + Thread.currentThread().getName());
	System.out.println("=====================");
	new MyThread("mythread1").start();
	new MyThread("mythread2").start();
}

2. 实现Runnable接口

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}

}


/*
 * 多线程,要注意是执行是乱序的,当然也有可能是顺序的. 
 * 1.让类继承Thread,重写run方法. 
 * 2.让类实现Runnable接口,重写run方法.
 * 推荐使用使用Runnable接口,因为类只能单继承,而接口可以多实现
 */
public static void main(String[] args) {
	System.out.println("main thread id:" + Thread.currentThread().getName());
	System.out.println("=====================");
	MyRunnable run1 = new MyRunnable();
	new Thread(run1, "myrun1").start();
	new Thread(run1, "myrun2").start();
}

看一下Thread源码

Thread类是精简过的,旨在了解上面说的2种方式多线程方式.

//Thread类也实现Runable接口
public class Thread implements Runnable {

	private Runnable target;

	public Thread() {
		init(null, null, "Thread-", 0);
	}

	public Thread(String name) {
		init(null, null, name, 0);
	}

	public Thread(Runnable target, String name) {
		init(null, target, name, 0);
	}

	private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
		init(g, target, name, stackSize, null, true);
	}

	private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc,
			boolean inheritThreadLocals) {
		/*
		 * 初始化线程的信息,如线程
		 */
	}
	
	private native void start0();

	public synchronized void start() {

		start0(); // 调用native函数start0,start0内部调用run函数

	}

	@Override
	public void run() {
		if (target != null) { // 如果继承Thread或实现Runable接口类不为空,变要调用该类重写的run方法
			target.run();
		}
	}

}
秋风 2017-06-30