Java多线程从0到1之线程创建(一)


 我们在开发中经常会用到多线程,尤其是在Android中,由于主线程的诸多限制,像网络请求,文件读取等一些耗时的操作都会用多线程来写,多线程说简单也简单,就是new Thread(),然后在start();说复杂也复杂,线程数太多会造成OOM,由此引入线程池,死锁,同步(synchronized),生产者/消费者,原子操作,Java并发集合等。所以深思之后打算写一个系列,记录从学校到工作自己对多线程的理解。


既然是从0开始,那么就先说一下什么是线程,它和进程有什么区别吧


1、什么是线程?它和进程有什么区别?Java中的线程有那些状态?

线程是一个程序执行的最小单元,是被系统独立调度和分派的基本单位,线程是依附于进程存在的,可以把线程看作是进程中的一个实体,一个进程中有一个或多个这样的实体,所以说线程不能独立于进程执行,一个进程中的多个线程是可以共享内存资源的。

Java线程的状态:新建状态,可运行状态,正在运行状态,阻塞状态,死亡状态。

新建状态(new): 当程序使用new新建了一个线程后,该线程就处于新建状态,线程还没有启动即还没有调用start方法。

可运行状态(runnable): 当线程调用start()方法后进入可运行状态,线程等待cpu分配资源

运行状态(running):线程拿到cpu的资源,开始执行线程体即执行run()方法

阻塞状态(block):如下情况线程会进入阻塞状态

线程自己调用sleep()方法,主动放弃cpu的资源

线程调用了一个阻塞的IO操作,如控制台等待用户的输入等

运行在当前线程里的其他线程t2调用join()方法,当前线程进入阻塞状态

死亡状态(dead):当前线程的run()方法执行完毕或者所依附进程的main方法执行完毕时,线程进入死亡状态,值得注意的是进入死亡状态的线程是不能在复活的,企图调用一个死亡线程的start()方法,将抛出异常。

Java多线程从0到1之线程创建(一)_第1张图片


2、线程的三种创建方式

集成Thrad类,重写run()方法:
public class MyThread extends Thread{
	@Override
	public void run() {
		//do somthing...
	}
	
	public static void main(String[] args) {
		new MyThread().start();
	}
}

实现runnable接口,重写run()方法
public class MyRunnableTest implements Runnable{
	
	@Override
	public void run() {
		// do somthing...
	}
	public static void main(String[] args) {
		MyRunnableTest myRunnableTest = new MyRunnableTest();
		new Thread(myRunnableTest).start();
	}
}

其实我们在平时开发的时候,对于一些简单的逻辑处理需要用到线程的一般不这么写,还有一种更简便的方法

new Thread(new Runnable() {
	@Override
	public void run() {
		// do somthing...
	}
}).start();


通过Callable和Future创建线程

public class CallableThreadTest implements Callable{
	public static void main(String[] args) {
		CallableThreadTest ctt = new CallableThreadTest();  
		FutureTask ft = new FutureTask<>(ctt);
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  
            if(i==2){  
                new Thread(ft).start();  
            } 
		}
		try {
			System.out.println("子线程的返回值:"+ft.get());
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Override
	public Integer call() throws Exception {
		return 1;
	}
}
新建一个类实现Callable接口,接口需要指定一个泛型的参数,这个参数也是子线程执行后返回值的类型,重写call()方法,call()方法就是子线程的执行体。

3、三种方法的对比

采用实现Runnable、Callable接口的方式创见多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。
使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
劣势是:
线程类已经继承了Thread类,所以不能再继承其他父类。


你可能感兴趣的:(java,android)