进程、线程、线程组、线程池

进程:进程是资源分配的最小单位;进程=独立的代码+数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1-n个线程;

线程:线程是CPU调度的最小单位;线程=堆栈+程序计数器+同一类线程共享的代码和数据空间,线程的切换开销较小;

线程组:线程可以分组,Java默认创建的线程都属于系统线程组;作用是:出于安全考虑;因为同一个线程组的线程可以相互修改对方的数据;如果不是同一个线程组中,则不能修改,所以可以保证数据安全;

线程池:专门用来存放很多线程的池子;作用是:出于效率考虑;由于线程的创建和结束都需要消耗系统资源,频繁的创建肯定是降低性能的。因此将线程放在线程池中,使得线程重复使用,可以省去线程的反复创建与销毁,从而节省时间,提高效率;

【线程池和线程组共同点】

1、都是管理一定数量的线程;

2、都可以对线程进行控制——休眠、唤醒、结束、创建、中断、暂停,但不一定包含全部这些操作。

设置线程任务的方式:Thread 、Runnable 、Callable (run/call方法)

创建并启动线程的方式:Thread的start();线程池的submit()方法

 

【线程的创建】

Thread

1、通过继承Thread类的方式,重写run方法,则设置了线程的任务;run()方法是线程的任务;

class MyThread extends Thread{}

创建线程并启动的方式:new MyThread().start();

2、通过实现Runnable接口的方式,实现run方法,则设置了线程的任务;run()方法是线程的任务;

class MyRunnable implements Runnable{

@Override

void run(){}

}

创建线程并启动的方式:new Thread(new MyRunnable()).start();

3、通过实现Callable接口的方式,实现call方法,则设置了线程的任务;call()方法是线程的任务;

class MyCallable implements Callable{

@Override

call(){ return T;}

}

创建线程并启动的方式:

CallablemyCallable = new MyCallable();

FutureTaskfutureTask = new FutureTask(myCallable);

new Thread(futureTask).start();

try{

futureTask.get();

}catch(Exception e){

e.printStackTrace();

}

Thread和Runnable的异同:

1、Thread是一个类,需要继承;Runnable是一个接口,需要实现;由于Java是单继承,所以推荐Runnable方式创建线程;

2、Thread类中的start方法启动线程后,事实上在运行时执行的是Runnable的run方法(Thread的源码中有一个Runnable target的属性,当我们调用thread的start方法时,事实就是运行时执行了target的run方法;start方法和run方法耦合在一起);而Runnable在启动线程时,是先new一个Runnable类的实例,在包装成一个Thread的实例,在执行start方法。就好像把线程的创建和具体的业务做了解耦,代码和数据独立。多线程下可以共享资源;

如:Runnable runnable = new MyRunnable();

Thread t1 = new Thread(runnable);

Thread t2 = new Thread(runnable);

t1.start();

t2.start();

示例中,创建了两个线程,最终使用了同一个Runnable实例。如果Runnable实例中包含了一个类变量,那么两个线程对这个变量操作就相互影响,这个变量就是共享的;

3、线程池只能放入Runable或Callable类线程,不能直接放入继承Thread的类。

Runnable相比Thread的优势:

1、适合多个相同的程序代码的线程去共享一个资源;

2、避免Java中单继承的局限性;

3、增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。(实现Runnable接口的方式,把设置线程任务和开启线程进行了分离(解耦),实现类中重写了run方法来设置线程任务,而创建Thread类对象调用start方法只是用来开启新的线程)

4、线程池只能放入Runable或Callable类线程,不能直接放入继承Thread的类。

Runnable和Callable的异同:

1、两个都是接口,需要实现;

2、Runnable的run方法没有返回值,也不能抛出异常;Callable的call方法有返回值,还支持通过泛型规定call的返回值,同时还会抛出异常;

3、Future是对Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。

4、Callable接口带来了灵活的线程使用体验,调用FutureTask的get方法,从而获取call方法的返回值;FutureTask的源码显示,它实现了RunnableFuture接口,而RunnableFuture又继承了Runnable和Future接口。这也解释了为什么FutureTask能够作为Thread构造方法的一个参数,同时又能够通过get方法取得返回值;

posted @ 2025-03-11 11:24  KLAPT  阅读(14)  评论(0)    收藏  举报