Java —— 多线程笔记 一、线程创建、启动、生命周期、线程控制

一、进程与线程

1、进程。每个运行中的程序就是一个进程,一般而言,进程有三个特征:

(1)、独立性。可以拥有自己独立的资源,拥有自己私有的地址空间。

(2)、动态性。主要是与程序的区别,程序是一个静态的指令集合,进程是一个动态的指令集合,即在进程中有个时间的概念。进程具有自己的生命周期和各种不同的状态,而程序不具备。

(3)、并发性。指各个进程可以在单独处理器上并发执行。

2、线程。一个进程内部可能包含多个顺序执行流,每个顺序执行流就是一个线程。


并发和并行性:

并发性(concurrency):同一时刻只有一条指令执行,但多条指令被快速轮换执行。

并行性(parallel):同一时刻有多条指令在多个处理器上同时执行。


多线程的优势:

(1)、易于通信。与分隔的进程相比,同一进程中线程之间的隔离程度较弱,所以更易于实现通信。

(2)、占内存资源少。同一进程多个线程之间共享进程的虚拟空间(共享的数据具体包括:进程代码段、进程的公有数据等),而不同进程必须分配各自的内存空间,所以线程所占内存资源更少。



二、线程的创建与启动

1、继承Thread 类创建;

2、实现Runnable 接口创建对象,再以此对象作为Thread 对象的目标(target);

3、实现Future 接口创建对象(Java5 开始),再以此对象作为Thread 对象的目标(target)。与实现Runnable 接口不同的是,Future 接口构造参数必须传一个Callable 接口对象,而Callable 接口的call()方法才是线程真正执行的方法,相当于run()方法,当它可以有返回值。另外,Java 已经提供了一个Future 接口的实现类FutureTask 类。

第3种方式示例:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class TestFuture {

	//Callable泛型接口定义真正执行的任务,泛型为返回值
	public static Callable<Integer> task = null;
	//Future 接口包装Callable 接口,并能获取Callable 接口call 方法的返回值,泛型为Callable 的泛型
	public static FutureTask<Integer> ft = null;
	
	public static void main(String[] args) {
		
		task = new Callable<Integer>(){

			@Override
			public Integer call() throws Exception {
				
				return new Integer(20);
			}};
		ft = new FutureTask<Integer>(task);
		//开启新线程,以Future 接口对象作为target
		new Thread(ft,"我的线程").start();

		try {
			boolean complete = false;
			while(!complete){
				if(ft.isDone()){
					System.out.println("线程返回的值:"+ft.get().intValue());
					complete = true;
				}
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
说明:

Future<T> 接口提供了三个方法:T get()获取包装的Callable 接口的call 方法的返回值、boolean cancel(...)取消该Future 关联的Callable 任务、boolean isCancelled()是否在Callable 任务正常完成前被取消的、boolean isDone()是否完成已完成。


三种方式特点比较:

1、实现Runnable 或Future 接口的方式:(1)、还可继承其它类;(2)、多个线程可共享一个target,适合多个线程处理同一份资源的情况;(3)、访问当前线程只能使用Thread.currentThread()方法。

2、实现Thread 类方式:(1)、编程更简单,但不能再继承其它类;(2)、访问当前线程只需使用this 即可。



三、线程的生命周期

1、新建状态:刚new 出来时的状态;

2、就绪状态:调用start()方法后的状态,此时还未真正进入运行状态;

3、运行状态:线程获得了CPU资源,执行run()方法的状态;

4、阻塞状态:

(1)、调用了sleep()方法主动放弃CPU资源;

(2)、该线程调用了一个阻塞式IO方法,在该方法返回前,该线程被阻塞;

(3)、该线程试图获得同步监视器(即试图执行与synchronize相关的语句块或方法),但同步监视器被其他线程持有;

(4)、线程在等待某个通知(notify);

(5)、调用了suspend()方法将线程挂起(最好别用,易导致死锁。要解除挂起,需调用resume()方法)。

5、死亡状态:

(1)、run()或call()方法执行完毕,善终;

(2)、线程抛出一个未捕获的异常(Exception)或错误(Error);

(3)、直接调用线程的stop()方法结束该线程(不推荐,易导致死锁)。


注意事项:

1、线程的start()方法只能调用一次,线程死亡后不能再start();

2、当主线程结束时,其他线程不受任何影响,不会随之结束;

3、线程的run()或call()方法不能手动调用,否则它将不作为线程执行体。



四、线程控制

1、join线程:

Thread 提供了一个线程等待另一个线程完成的方法——join()方法。某线程调用此方法后,则该线程所在的线程才会继续执行,示例:

class TestThread extends Thread {
	
	public static void main(String args[]) throws InterruptedException{
		
		Thread t = new TestThread();
		for (int i = 0; i < 10; i++) {
			if(i==3){
				t.start();
				t.join();
			}
			System.out.println("主线程"+i);
		}
	}
	
	public void run(){
		for(int i=0;i<10;i++){
			System.out.println("被join的线程:"+i);
		}
	}
}
结果:

主线程0
主线程1
主线程2
被join的线程:0
被join的线程:1
被join的线程:2
被join的线程:3
被join的线程:4
被join的线程:5
被join的线程:6
被join的线程:7
被join的线程:8
被join的线程:9
主线程3
主线程4
主线程5
主线程6
主线程7
主线程8
主线程9

2、后台线程

后台线程(Daemon Thread)又称守护线程或精灵线程,特征:(1)、所有前台线程都死亡后,后台线程会自动死亡,并不会执行完再死亡。JVM垃圾回收线程是典型的守护线程。

设置线程为守护线程:调用Thread 对象的 setDaemon(true)方法设置线程为守护线程(必须在start()方法前调用)。

判断线程是否为守护线程:isDaemon()。


3、线程睡眠

Thread 类的静态方法:static void sleep(long millis),线程睡眠millis 毫秒,并处于阻塞状态,不会竞争CPU资源。


4、线程让步

Thread 类的静态方法:static void yield(),线程被暂停,让系统的调度器重新调度一次,与sleep方法区别是,该线程完全可能又获得执行权(只有此一个线程时,概率就是百分百)。


5、sleep与 yield 方法区别

(1)、优先级问题。调用sleep()后,其它线程竞争cpu资源时不考虑线程优先级;但yield()方法只给优先级相同或更高的线程执行机会;

(2)、sleep()会进入阻塞状态,而yield()不会;

(3)、sleep()方法声明了抛出 InterruptedException 异常,但 yield()方法没有声明抛出任何异常;

(4)、sleep()方法比yield()方法有更好的可移植性(暂时不理解),通常不建议使用yield()方法。


6、改变线程优先级

优先级高的线程会获得更多的执行机会!优先级范围为1-10.

设置线程优先级:Thread 对象的setPriority(int newPriority);

获取线性优先级:Thread 对象的getPriority();

3个静态常量:

Thread.MAX_PRIORITY:10;

Thread.MIN_PRIORITY:1;

Thread.NORM_PRIORITY:5.



线程的各套控制方法整理:

sleep()、yield()可为一类:重新调度;

suspend() 与 resume()为一套:中途暂停与重新启用;

wait() 与notify() 或notifyAll() 为一套:等待与唤醒等待;

join() 方法为一类:执行完此线程后再继续执行该线程所在的线程。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值