Java多线程 ----(1)多线程基础

1、什么是多线程和使用多线程的意义
2、多线程基础知识点框架图
3、实现多线程的三种方式
4、三种方式对比

1、什么是多线程合使用多线程的意义

  • 单进程单线程:一个人在一个桌子上吃菜;(开桌子的意思是指创建进程。开销这里主要指的是时间开销。)
  • 单进程多线程:多个人在同一个桌子上一起吃菜;
  • 多进程单线程:多个人每个人在自己的桌子上吃菜;

多线程的问题是多个人同时吃一道菜的时候容易发生争抢,例如两个人同时夹一个菜,一个人刚伸出筷子,结果伸到的时候已经被夹走菜了。此时就必须等一个人夹一口之后,在还给另外一个人夹菜,也就是说资源共享就会发生冲突争抢。

  • 对于 Windows 系统来说,【开桌子】的开销很大,因此 Windows 鼓励大家在一个桌子上吃菜。因此 Windows 多线程学习重点是要大量面对资源争抢与同步方面的问题。
  • 对于 Linux 系统来说,【开桌子】的开销很小,因此 Linux 鼓励大家尽量每个人都开自己的桌子吃菜。这带来新的问题是:坐在两张不同的桌子上,说话不方便。因此,Linux 下的学习重点大家要学习进程间通讯的方法。
  • 做个实验:创建一个进程,在进程中往内存写若干数据,然后读出该数据,然后退出。此过程重复 1000 次,相当于创建/销毁进程 1000 次。在我机器上的测试结果是:UbuntuLinux:耗时 0.8 秒;Windows7:耗时 79.8 秒。两者开销大约相差一百倍。这意味着,在 Windows 中,进程创建的开销不容忽视。换句话说就是,Windows 编程中不建议你创建进程,如果你的程序架构需要大量创建进程,那么最好是切换到 Linux 系统。

2、 多线程基础知识点框架图

image.png

3、实现多线程的三种方式

(1) 创建线程的第一种方式:继承Thread类,覆盖其中的run方法

public class Ticket extends Thread{

    private static int ticketCount = 100;//此处必须是static,否则每个线程都会有100张票

    public void run(){
        while(true){
            if(ticketCount>0){
                System.out.println(Thread.currentThread().getName()+"------"+ticketCount--);
            }
        }
    }
}


public static void main(String args[]){      
        //启动四个线程,分别执行
        Ticket t1 = new Ticket();
        Ticket t2 = new Ticket();
        Ticket t3 = new Ticket();
        Ticket t4 = new Ticket();

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

多个线程共享一个资源

image.png

(2) 实现Runnable接口,实现其中run方法

步骤:
1、定义类实现Runnable接口。
2、覆盖Runnable接口中的run方法中。将线程要运行的代码存放在改run方法中。
3、通过Thread类建立线程对象。
4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。自定义的run方法所属的对象是Runnable接口的子类对象。

5、调用Thread类的start方法开启线程并调用Runnable接口的子类的run方法。

//创建Ticket类,实现Runnable方法
public class Ticket implements Runnable{
   
    private int ticketCount = 100;
    public void run(){
        while(true){
            if(ticketCount>0){
                System.out.println(Thread.currentThread().getName()+"------"+ticketCount--);
            }
        }
    }
}



public static void main(String args[]){
        Ticket t = new Ticket();

        //启动四个线程,共享Ticket

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
}

(3) 实现Callable接口,重写call()方法

Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。

Callable接口和Runnable接口的不同之处:

  • Callable规定的方法是call,而Runnable是run
  • Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能;
  • Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。

多线程的实现有以下4个步骤:

step1 创建一个线程,创建Callable的实现类Race,并且重写call方法;

ExecutorService ser=Executors.newFixedThreadPool(线程数目);
Race tortoise = new Race();

step2 得到Future对象

Future<Integer> result=ser.submit(tortoise);

step3 获取返回值

int num=result.get();

step4 停止服务

ser.shutdown();

一个完整的例子

1 定义类,实现Callable接口

/**
 * 方法4:不通过FutureTask,来实现Callable实例作为线程的执行体
 */
public class CreateThread_4 implements Callable<String> {

    private static int ticket;

    public CreateThread_4(int ticket){
        this.ticket = ticket;
    }

    public String call() throws Exception {
        return "this task num is "+ ticket;
    }
    
}

2 单线程提交打印

  • Callable接口中的call()方法的返回类型为Future接口类型,Future接口提供一个实现类FutureTask。FutureTask 还实现了Runnable接口,由于Thread的执行体只接受Runnable接口实例,所以如果想Callable实例作为Thread的执行体就必须通过FureTask来作为桥梁,即:正常情况下我们是将一个Runable接口实例设置进去(在这里这个实例即是FutureTask对象,因为FutureTask实现了Runable接口,FutureTask对象即是Runnable接口的一个实例,而Callable接口实例的类型是Future类型,而FutureTask实现了Future接口,所以Callable接口实例即相当于FutureTask实例:ps:其实不是,但是可以这样理解)。

下面看Callable接口实例作为Thread的执行体。

/**
     * 一个线程
     */
    @Test
    public void createThread_4_call_1() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        Future<String> future = threadPool.submit(new CreateThread_4(190));
        try {
            System.out.println(future.get());
        } catch (Exception e) {

        } finally {
            threadPool.shutdown();
        }
    }

3 多线程提交打印

  • 下面还介绍一种不通过FutureTask,来实现Callable实例作为线程的执行体
 /**
     * 多个线程
     */
    @Test
    public void createThread_4_call() {
        ExecutorService exec = Executors.newCachedThreadPool();
        List<Future<String>> list = new ArrayList<Future<String>>();

        for (int i = 0; i < 30; i++) {
            CreateThread_4 callable = new CreateThread_4(i);//创建Callable接口实例
            list.add(exec.submit(callable));//将callable接口实例提交进线程池
        }

        for (Future<String> fs : list) {
            try {
                System.out.println(fs.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

4、三种方法的对比

第一种方式(继承)和第二种方式(实现)的区别
1、继承Thread,线程代码放在Thread的run方法中;
2、实现Runnable,线程代码放在接口子类的run方法中;该实现方式可以避免单继承的局限性;
3、实现Callable和Runnable接口都能够创建线程的执行体,但是Runnable接口并不返回任何值,如果你希望任务在完成的时候能够返回一个值,就可以通过实现Callable接口来实现。在JavaAPI中是这样描述Callable接口的:Callable和Runnable相似,他们的类实例都能够被其他Thread执行,但是Callable接口能够返回一个值或者抛出一个异常,Runnable却不能,实现Callable接口需要重写其唯一的call()方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351