- 多进程:在操作系统能同时运行多个程序
- 多线程:在同一个应用程序中,有多个任务同时进行
由于进程是由操作系统控制的,所以并发指的是线程级别的
Java中线程的创建有两种方式:Thread类和Runnable接口(Thread类最终也是实现Runnable接口)
- java只能继承一个类,能实现多个接口,所以继承者只能继承一个Thread,却能实现无数个Runnable。
Thread:
public class A{
public static void main(String[] args) {
A0 a0=new A0();
A0 a1=new A0();
a0.start();
a1.start();
}
}
class A0 extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
Runnable:
public class B {
public static void main(String[] args) {
B0 b0=new B0();
Thread t0=new Thread(b0);
t0.start();
B0 b1=new B0();
Thread t1=new Thread(b1);
t1.start();
}
}
class B0 implements Runnable {
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
中断线程
第一种方式:粗暴的stop
一般情况下不会用stop终止线程。因为使用stop会强制进程终止,但会对CPU有损伤。
public class A{
public static void main(String[] args) {
A0 a0=new A0();
A0 a1=new A0();
a0.start();
a1.start();
}
}
class A0 extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
if(i==50){
stop();
//break;//的方式也优于stop
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
第二种方式:interrupt
JDK推荐使用Interrupr来中断线程,但是使用Interrupt是有限制的:只有线程处在sleep;wait;join;状态的时候才能用interrupt来将进程中断。
调用interrupt方法并不会中断一个正在运行的进程,也就是说处于Running状态的线程并不会因为被中断而终止。仅仅改变了内部维护的中断表示而已。
public class A{
public static void main(String[] args) {
A0 a0=new A0();
A0 a1=new A0();
a0.start();
a1.start();
}
}
class A0 extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
if(i==50){
try {
Thread.sleep(5000);//线程暂停5000ms后被重新唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
线程池
线程池原理:
Java中的线程池主要用于管理线程组及其运行状态,以便Java虛拟机更好地利用CPU资源。
Java线程池的的工作原理为: JVM先根据用户参数创建一定数量的可运行的线程任务,并将其放入队列中,在线程创建后启动这些任务,如果线程数量超过了最大线程数量(用户设置的线程池大小),则超出数量的线程排队等候,在有任务执行完毕后,线程池调度器会返现有可用的线程,进而再次从队列中取出任务并执行。
线程池的主要作用是线程复用、线程资源管理、控制操作系统的最大并发数、以保证高效(通过线程资源复用实现)且安全(通过控制最大线程并发数实现)地运行。使用线程池启动线程:处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class C {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService service=Executors.newCachedThreadPool();
//调用线程池newCachedThreadPool(动态的) newSingleThreadExecutor(一个) newFixedThreadPool(固定的)
List list=new ArrayList();
for(int i=0;i<10;i++){
C0 c=new C0(i+" ");
Future f=service.submit(c);
list.add(f);
}
service.shutdown();
for(Future f:list){
System.out.println(f.get().toString());
}
}
}
class C0 implements Callable{
String name;
C0(String name){
this.name=name;
}
@Override
public Object call() throws Exception {
return this.name+"is ok";
}
}
三种创建基本线程的区别
- 使用Runnable接口:将线程代码和线程数据分隔开,形成清晰的模型可以实现多种接口
- 使用Thread类:不能再继承其他类,编写简单可以直接操纵线程
- 使用Callable回调接口:
- Callable接口规定的方法是call();而Runnable规定的方法是run()。
- Callable任务执行后有返回值,而Runnable的任务是没有返回值的
- call()的方法可以抛出异常,run()方法不能抛出异常。
- 运行callable任务可以得到一个Future对象,Future表示异步计算的结果,它提供了检查计算是否完成的办法以等待计算的完成,并且检索计算的结果,通过Future对象可了解任务执行情况,可以取消任务的执行。
- Callable是类似于Runnable的接口,实现Callable的类和实现Runnable的类都是可被其他任务线程执行的任务



