Java多线程(一)认识多线程

认识多线程

    Java中有关多线程的只是虽然只有几章节,但是真正扩展开来几本书都不用,让我们从基础开始,一步步的学习多线程相关的知识。

1.基本概念介绍
    进程:系统中分配资源的一个调度单位。
    线程:也被称为轻量级进程,是进城中的调度单位。
    并发:多个指令轮流执行。
    并行:多个执行同时执行。
    一个程序至少有一个进程,一个进程中可以有多个线程。
2.多线程的基本实现
要想实现多线程,有以下三种方式:
(1) 继承Thread类,

    操作步骤:

  1. 定义Thread的子类,重写run()方法,作为线程执行体;
  2. 创建实例;
  3. 调用start()方法。
  我们用多线程中比较常见的一个场景来举例:车站有三个窗口一起卖10张火车票。

    测试类:

package com.ljw.Thread.TestTickets;

/**
 * Created by liujiawei on 2018/7/5.
 */
public class SellTickestByThread extends Thread{

    public SellTickestByThread(String name) {
        super(name);
    }

    int tickets = 10;


    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(tickets > 0)
            System.out.println(getName() + "卖了以后还剩下==" + tickets--);
        }
    }

    public static void main(String[] args) {
        SellTickestByThread thread = new SellTickestByThread("一窗口");
        SellTickestByThread thread1 = new SellTickestByThread("二窗口");
        SellTickestByThread thread2 = new SellTickestByThread("三窗口");
        thread.start();
        thread1.start();
        thread2.start();

    }
}

运行结果:


    运行上面的代码以后,我们可以看到多线程的确发挥了作用,三个窗口都开始售卖票了,但是每个窗口都卖了十张票,一共卖了三十张,这明显是不对的。这是因为继承Thread类的多线程无法共享线程类的实例变量。


(2)实现Runnable接口:

操作步骤:

  1. 实现Runnable,重写run()方法作为线程执行体;
  2. 创建Runnable类的实例,以此作为Thread的target来创建Thread实例。

我们还是用上面的例子来测试代码:

package com.ljw.Thread.TestTickets;

/**
 * Created by liujiawei on 2018/7/5.
 */
public class SellTicketsByRunnable implements Runnable{
    int tickets = 10;
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(tickets > 0)
            System.out.println(Thread.currentThread().getName() + "卖出以后还剩" + tickets--);
        }
    }


    public static void main(String[] args) {
        SellTicketsByRunnable sellTicketsByRunnable = new SellTicketsByRunnable();

        Thread thread = new Thread(sellTicketsByRunnable,"窗口一");
        Thread thread2 = new Thread(sellTicketsByRunnable,"窗口二");
        Thread thread3 = new Thread(sellTicketsByRunnable,"窗口三");

        thread.start();
        thread2.start();
        thread3.start();
    }

}

    运行结果:


    我们可以看到,这次的结果好像是我们想要的情况,窗口卖票,但票的总数不会变多,可惜的是顺序好像不太多,这个我们以后在说。我们可以知道实现Runnable接口也可以实现多线程,而且还可以共享线程类的实例变量。


(3)使用Callable和Future创建线程:
    Callable接口是Runnable接口的增强版,它提供了一个call()方法作为线程执行体,但是他可以有返回值,也可以返回报错时的异常。它和Future对象配合起来使用。
1》创建Callable接口的实现类,重写call()方法作为线程实现体,且call()方法有返回值;
2》使用FutureTask对象来包装Callable对象,同时封装了call()方法的返回值;
3》使用FutureTask对象作为Thread对象的target创建Thread实例
4》使用FutureTask对象的get()方法可以获取call()方法的返回值。
下面我们看下测试代码:
package com.ljw.Thread.TestTickets;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * Created by liujiawei on 2018/7/6.
 */
public class SellTicketsByFuture implements Callable{
    int tickets = 10;

    @Override
    public Object call() throws Exception {
        for (int i = 0; i < 100; i++) {
            if(tickets > 0)
            System.out.println(Thread.currentThread().getName() + "卖出还剩" + tickets--);
        }
        return null;
    }


    public static void main(String[] args) {
        SellTicketsByFuture sellTicketsByFuture = new SellTicketsByFuture();
        FutureTask task = new FutureTask(sellTicketsByFuture);
        FutureTask task2 = new FutureTask(sellTicketsByFuture);
        Thread thread = new Thread(task,"窗口一");
        Thread thread2 = new Thread(task2,"窗口二");
        thread.start();
        thread2.start();
    }



}

输出结果:


    可以看到使用Callable接口一样实现多线程的功能。



3.三种多线程创建方式的对比.
 采用Runnable和Callable接口的优缺点:
优点:(1)实现接口不影响继承,还可以再继承其他类;
 (2)这两者都可以共享同一个target,可以分享同一个资源;
缺点:编程略复杂,获取线程要通过Thread.currentThread()这种方式


采用Thread继承的优缺点:
优点:(1)编程简单
         (2)获取线程对象方便,this就可以;
缺点:无法继承其他类,无法共享target的实例变量。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值