Java多线程之一

1、线程的概述
进程定义:“进程是进程实体(PCB、程序段、数据段)的运行过程,是系统进行资源分配和调度的一个独立单元”。引入进程的目的,是为了使多道程序并发执行,以提高资源利用率和系统吞吐量;而引入线程的目的是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。
进程是处于运行过程中的程序,是系统进行资源分配和调度的一个独立单元。一般而言具有以下特征:

  • 独立性:进程是系统中独立存在的实体,可以拥有自己的资源,每一个进程都拥有自己独立的地址空间。
  • 动态性:动态性这就是进程和程序的主要区别。进程具有自己的生命周期和各种不同的状态,这些概念在程序中是不具有的。
  • 并发性:多个进程可以在单处理器上并发执行,多个进程间互不干扰。

进程和线程的区别:

  • 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动。在传统的操作系统中,进程是系统进行资源分配和调度的一个基本单元,在引入线程的操作系统中,线程是独立调度的基本单元,进程是资源拥有的基本单元。
  • 线程是CPU调度的基本单位,它是比进程更小的能独立运行的基本单位.
  • 线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但同一个进程的其他的线程共享进程所拥有的全部资源。
  • 一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

本质区别:进程之间拥有独立的地址空间,不共享地址空间; 而线程是共享进程的地址空间

在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态。多个线程共享堆内存(heap memory),因此创建多个线程去执行一些任务会比创建多个进程更好。

在实际的应用中,多线程是非常有用的,一个浏览器必须能同时下载多个图片;一个Web服务器必须能同时响应多个用户的请求;Java虚拟机在后台进行的垃圾回收等等。

2、进程的创建和启动
java使用Thread类代表进程,所有的进程对象都必须是Thread类和其子类的实例。每条线程的作用是完成一定的任务,实际上就是执行一段程序流。
创建线程的三种方式:
方式一:继承Thread类创建线程,继承Thread类,从写线程执行体Run()方法。

public class MyThread extends Thread{
    private int i;
    @Override
    public void run() {
        for(;i<100;i++){
            //线程继承Thread类时,可以直接调用getName()方法来返回当前线程的名
            //如果想获取当前线程,直接使用this即可
            //Thread的getName()返回当前线程的名字
            System.out.println(Thread.currentThread().getName()+" "+i);         
        }
    }
}


public class ThreadTest {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Thread myThread1 = new MyThread();    
                Thread myThread2 = new MyThread();     
                myThread1.start();                     
                myThread2.start(); 
            }
        }
    }
}

方式二:实现Runnable接口创建线程
1、实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体;
2、创建Runnable实现类的实例,并以此实例作为Thread的构造函数的参数来创建线程。

public class MyRunnable implements Runnable {
    private int i=0;
    @Override
    public void run() {
        for(;i<100;i++){
            //当前线程类实现Runnable接口时,如果想获取当前线程,可以使用Thread.currentThread()方法
            //Thread的currentThread()返回当前线程
            //可以被多个线程共享
            System.out.println(Thread.currentThread().getName()+" "+i);         
        }       
    }
}


public class ThreadTest {

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象
                Thread thread1 = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程
                Thread thread2 = new Thread(myRunnable);
                thread1.start(); // 调用start()方法使得线程进入就绪状态
                thread2.start();
            }
        }
    }
}

方式三:.使用Callable和Future接口创建线程。
具体是创建Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象创建实例,并以此实例作为Thread的构造函数的参数来创建线程。FutureTask实现了Callable接口和Runnable接口。

class MyCallable implements Callable<Integer> {
    private int i = 0;
    // 与run()方法不同的是,call()方法具有返回值
    @Override
    public Integer call() {
        int sum = 0;
        for (; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            sum += i;
        }
        return sum;
    }
}


public class ThreadTest {
    public static void main(String[] args) {
        // 创建MyCallable对象
        Callable<Integer> myCallable = new MyCallable();  
        //使用FutureTask来包装MyCallable对象  
        FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); 
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
            //FutureTask对象作为Thread对象的target创建新的线程
                Thread thread = new Thread(ft);   
                thread.start();
            }
        }
        System.out.println("主线程for循环执行完毕..");        
        try {
            //取得新创建的新线程中的call()方法返回的结果
            int sum = ft.get();            
            System.out.println("sum = " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

总结一下吧:

实现Runnable接口比继承Thread类所具有的优势:

1)多个线程共享一个traget对象,适合多个相同的线程去处理同一个资源

2)线程实现了Runnable接口,还可以继承其他类;

3)增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

JDK1.5中提出的Callable接口是Runnable接口的增强版,Callable接口也提供了一个call()方法,可以作为线程执行体。功能更加强大:

1)call()方法可以有返回值;

2)call()方法可以声明抛出异常。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值