并发编程系列(一)线程的创建

多线程

Java给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行内容。

多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。

进程: 一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

线程 : 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位;

多线程能满足程序员编写非常有效率的程序来达到充分利用CPU的目的,因为CPU的空闲时间能够保持在最低限度。

线程的生命周期

在这里插入图片描述
线程共包括以下 5 种状态:

  1. 新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
  2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
  3. 运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
  4. 阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (01) 等待阻塞 – 通过调用线程的wait()方法,让线程等待某工作的完成。
    (02) 同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
    (03) 其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  5. 死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程优先级

在java中,线程的优先级的范围是MIN_PRIORITY(1)和MAX_PRIORITY(10),默认的优先级是NORM_PRIORITY(5);优先级高的不一定会比优先级低的先执行。

如何创建一个线程

1.继承Thread类

定义Thread类的子类,并重写该类的 run() 方法,该 run() 方法的方法体就代表了线程需要完成的任务。

public class HelloThread extends Thread{
 
    @Override
    public void run() {
        System.out.println("继承Thread类--创建线程");
    }
 
    public static void main(String[] args) {
        HelloThread ht = new HelloThread();
        ht.start();
    }
}

2.实现Runnable接口

定义Runable接口的实现类,并且重写该接口的run() 方法,该run() 方法的方法体就是线程的线程执行体
创建Runable实现类的实例,并且以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。

public class HelloRunable implements Runnable{
    @Override
    public void run() {
        System.out.printf("实现Runable 接口创建线程");
    }
 
    public static void main(String[] args) {
        HelloRunable helloRunable = new HelloRunable();
        Thread thread = new Thread(helloRunable);
        thread.start();
    }
}

3.Callable接口

使用Callable创建线程和Runnable接口方式创建线程比较相似,不同的是,Callable接口提供了一个call() 方法作为线程执行体,而Runnable接口提供的是run()方法,同时,call()方法可以有返回值,而且需要用FutureTask类来包装Callable对象。

public class MyCallable implements Callable {
     @Override
    public Integer call() {
        int sum = 0;
        for (int i =0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            sum += i;
        }
        return sum;
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        Callable<Integer> myCallable = new MyCallable();    // 创建MyCallable对象
        FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象

        Thread thread = new Thread(ft);   //FutureTask对象作为Thread对象的target创建新的线程
        thread.start();     //线程进入到就绪状态
        try {
            int sum = ft.get();  //取得返回的结果
            System.out.println("sum = " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

总结:

实现Runnable接口相对于继承Thread类来说,有如下的显著优势:
1 .适合多个相同代码的线程去处理同一个资源的情况
2.可以避免由于java的单继承特性带来的局限
3.增强了程序的健壮性,代码能够被多个线程共享,代码与数据时独立的

当需要线程执行完有返回结果,我们需要选择Callable创建线程。

发布了12 篇原创文章 · 获赞 0 · 访问量 338

猜你喜欢

转载自blog.csdn.net/fd135/article/details/104377519
今日推荐