java 多线程

一个任务通常就是一个程序,每个运行中的程序就是一个进程,每当一个程序运行时,内部可能包含多个顺序执行流,没个顺序执行流就是一个线程。

       每当一个程序进入内存运行时,即变成一个进程,进程是处于运行过程中的程序,并具有一定的而独立能力,进程是系统进行资源分配的一个独立的单位。

       进程的三个特征:

       独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,没一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下爱,一个用户进程不可与直接访问其他进程的地址空间。

       动态性,进程与程序的区别再于,程序只是一个静态的指令集和,而进程是一个正在系统中活动的指令集和。进程中加入的时间的观念,进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的。

       并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。

并发和并行是两个不同的概念,并行是指的在同一个时刻,有多条指令在多个处理器上同时执行;并发指的是同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,是指在宏观上具有多个进程同时执行的效果。

       多线程扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务。京城也被乘坐轻量级进程,线程是进程的执行单元。线程在程序中是独立的、并发的执行流。当进程被初始化后,主线程就被创建了。对于绝大多数的应用程序来说,通常有一个主线程,但是也可以在该进程内创建多条顺序执行流,这些顺序执行流就是线程,没个线程也是相互独立的。

       线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的对战、自己的程序计数器和自己的局部变量,但是不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源。因为多个线程共享父进程里的全部资源,因此编程更加方便,但是要必须更加小心,因为需要确保线程不会妨碍同一进程里的其他线程。

       线程可以完成一定的任务,可以与其他线程共享父进程的共享便来那个以及部分环境变量,相互之间协同完成进程所要的任务。

       线程可以是独立运行的,它并不知道进程中是否还有其他的线程存在。线程的抢占式的,也就是说,当前的运行的线程,任何时候可能被挂起,以便另一个线程运行。

多线程的创建以及启动

  1. 继承Thread类创建线程类
    1. 定义Thread类的子类,并重写类的run()方法,该run方法的方法体就代表了线程需要完成的任务。因此run方法是线程的执行体。
    2. 创建Thread类的子类,即创建Thread子类的实例,即创建了线程对象。
    3. 调用线程对象的start方法来启动线程。

代码如下:

public class FirstThread extends Thread
{
    private int i ;
    // 重写run方法,run方法的方法体就是线程执行体
    public void run()
    {
        for ( ; i < 100 ; i++ )
        {
            // 当线程类继承Thread类时,直接使用this即可获取当前线程
            // Thread对象的getName()返回当前该线程的名字
            // 因此可以直接调用getName()方法返回当前线程的名
            System.out.println(getName() +  " " + i);
        }
    }
    public static void main(String[] args)
    {
        for (int i = 0; i < 100;  i++)
        {
            // 调用Thread的currentThread方法获取当前线程
            System.out.println(Thread.currentThread().getName()
                +  " " + i);
            if (i == 20)
            {
                // 创建、并启动第一条线程
                new FirstThread().start();
                // 创建、并启动第二条线程
                new FirstThread().start();
            }
        }
    }
}

Main方法为线程的主线程体。

  1. 实现Runnable类创建多线程
    1. 定义Runnable接口的实现类,并重写该接口的run方法。该run方法的方法体,同样是该线程的执行体。
    2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

其实对于Target的理解就是,在Thread的构造函数中有好多种,Thread构造函数中传入一个实现了Runnable接口的实体类,然后最后会调用该实体类的重写的run方法。如果定义两个new Thread,但是构造函数中传入的参数都是同一个Runnable接口的实现类,那最终的结果是两个线程共享Runnable实现接口的实体类,其变量也共享

// 通过实现Runnable接口来创建线程类
public class SecondThread implements Runnable
{
    private int i ;
    // run方法同样是线程执行体
    public void run()
    {
        for ( ; i < 100 ; i++ )
        {
            // 当线程类实现Runnable接口时,
            // 如果想获取当前线程,只能用Thread.currentThread()方法。
            System.out.println(Thread.currentThread().getName()
                + "  " + i);
        }
    }

    public static void main(String[] args)
    {
        for (int i = 0; i < 100;  i++)
        {
            System.out.println(Thread.currentThread().getName()
                + "  " + i);
            if (i == 20)
            {
                SecondThread st = new SecondThread();     // ①
                // 通过new Thread(target , name)方法创建新线程
                new Thread(st , "新线程1").start();
                new Thread(st , "新线程2").start();
            }
        }
    }
}
  1. 使用Callable和Future创建线程
    1. 创建Callable接口的实现类,并实现call()方法,该call方法可以作为线程的执行体,且该call方法有返回值,再创建Callable实现类的实例。
    2. 使用FutureTask类来包装Callable对象。该FutureTask对象封装了该Callable对象的call方法的返回值。
    3. 使用FutureTask对象作为Thread对象的target创建并启动新的线程。
    4. 调用FutureTask对象的get方法来获取子线程执行结束后的返回值。

 

public class ThirdThread
{
	public static void main(String[] args)
	{
		// 创建Callable对象
		ThirdThread rt = new ThirdThread();
		// 先使用Lambda表达式创建Callable<Integer>对象
		// 使用FutureTask来包装Callable对象
		FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
			int i = 0;
			for ( ; i < 100 ; i++ )
			{
				System.out.println(Thread.currentThread().getName()
					+ " 的循环变量i的值:" + i);
			}
			// call()方法可以有返回值
			return i;
		});
		for (int i = 0 ; i < 100 ; i++)
		{
			System.out.println(Thread.currentThread().getName()
				+ " 的循环变量i的值:" + i);
			if (i == 20)
			{
				// 实质还是以Callable对象来创建、并启动线程
				new Thread(task , "有返回值的线程").start();
			}
		}
		try
		{
			// 获取线程返回值
			System.out.println("子线程的返回值:" + task.get());
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}

线程创建三种方式的比较:

通过继承Thread类或者是Callable以及Runnable接口都可以实现多线程,不过使用接口的方式,可以让实体类继承其他的类,接口的方式大致相同,只是一个有返回值(Callable)一个没有返回值(Runnable),该种方式还可以共享同一个变量,适合多个线程处理同一个任务的情况。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值