JavaSE多线程《一》

一· 首先了解一下什么是进程?线程?

进程:操作系统中一个程序的执行周期称为一个进程。

线程:一个程序同时执行多个任务。通常,每一个任务就称为一个线程。与进程相比较,线程更"轻量级",创建、撤销一个线程比启动一个新进程开销要小的多。没有进程就没有线程,进程一旦终止,其内的线程也将不复存在。

线程和进程的区别是什么?

多进程与多线程区别:本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之间的通信比进程之间通信更有效、更方便。

什么是高并发?

高并发:访问的线程量非常非常高

高并发带来的问题?

高并发带来的问题:服务器内存不够用,无法处理新的请求。

一个线程,从创建到运行结束,拥有三种不同的状态:

在这里插入图片描述
从图片可以详知:线程的三种状态为 就绪状态 运行状态 以及 阻塞状态。

二· JAVA多线程的实现:

2.1 通过继承Thread类实现多线程

java.lang.Thread是一个线程操作的核心类。新建一个线程最简单的方法就是直接继承Thread类,而后覆写该类中的run()方法(就相当于主类中的main方法)

package com.revision.Thread;

public class MyThread extends Thread {
    private String title;

    public MyThread(String title) {
        this.title = title;
    }

    @Override
    public void run() {
        //所有线程都从这里开始
        for(int i = 0;i <= 10;i++){
            System.out.println(this.title + ", i = " + i);
        }
    }

    public static void main(String[] args) {
        MyThread mt1 = new MyThread("byl1");
        MyThread mt2 = new MyThread("byl2");
        MyThread mt3 = new MyThread("byl3");
        MyThread mt4 = new MyThread("byl4");
        mt1.run();
        mt2.run();
        mt3.run();
        mt4.run();
    }
}


当现在有了线程的主体类之后,很自然我们就会想到产生线程类的实例化对象而后调用run()方法。实际上,我们不能够直接去调用run()方法

这个时候只是做了一个顺序打印,和多线程一点关系都没有。正确启动多线程的方式是调用Thread类中的start()方法

package com.revision.Thread;

public class MyThread extends Thread {
    private String title;

    public MyThread(String title) {
        this.title = title;
    }

    @Override
    public void run() {
        //所有线程都从这里开始
        for(int i = 0;i <= 10;i++){
            System.out.println(this.title + ", i = " + i);
        }
    }

    public static void main(String[] args) {
        MyThread mt1 = new MyThread("byl1");
        MyThread mt2 = new MyThread("byl2");
        MyThread mt3 = new MyThread("byl3");
        MyThread mt4 = new MyThread("byl4");
        /*mt1.run();
        mt2.run();
        mt3.run();
        mt4.run();*/
        //这里我们不再使用run()方法开启线程
        mt1.start();
        mt2.start();
        mt3.start();
        mt4.start();
    }
}

在这里插入图片描述
可以看到这次执行的顺序已经是被“打乱了的“,也就是在交替执行

2.2 使用Runnable()接口实现多线程

Thread类的核心功能就是用于线程启动,如果为了启动一个线程而继承这个类,就会产生java单继承的局限性,所以我们有时也需要通过Runnable()接口去实现多线程

观察Runnable()接口

@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}

利用实现Runnable()接口,写出代码:

package com.revision.Thread;

public class MyThread1 implements Runnable {

    private String title;

    public MyThread1(String title) {
        this.title = title;
    }

    @Override
    public void run() {
        //所有线程都从这里开始
        for(int i = 0;i <= 10;i++){
            System.out.println(this.title + ", i = " + i);
        }
    }

    public static void main(String[] args) {
        MyThread1 mt1 = new MyThread1("byl");
        mt1.
    }
}

此时我们发现 并没有start()方法供我们使用,应为Runnable()接口里只有一个run()方法。
那么此时就需要关注Thread类提供的构造方法。

我们发现Thread类的构造方法为:

public Thread(Runnable target)

所以我们利用Thread构造器来接受一个实现了runnable接口的对象

package com.revision.Thread;

public class MyThread1 implements Runnable {

    private String title;

    public MyThread1(String title) {
        this.title = title;
    }

    @Override
    public void run() {
        //所有线程都从这里开始
        for(int i = 0;i <= 10;i++){
            System.out.println(this.title + ", i = " + i);
        }
    }

    public static void main(String[] args) {

        MyThread1 mt1 = new MyThread1("byl1");
        MyThread1 mt2 = new MyThread1("byl2");

        new Thread(mt1).start();
        new Thread(mt2).start();
    }
}

在这里插入图片描述
此时我们看到 结果是交替运行,说明启动多线程也成功!

我们也可以利用 匿名内部类的方式启动多线程,或是利用lambda表达式:

1.利用匿名内部类:

package com.revision.Thread;
//利用匿名内部类实现多线程的启动
public class MyThread2 {

    public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i = 0;i <= 10;i++){
                        System.out.println(i);
                    }
                }
            }).start();
    }
}

2.利用lambda表达式:

public class TestDemo {
public static void main(String[] args) {
Runnable runnable = () -> System.out.println("Hello World");
new Thread(runnable).start();
		}
}

2.3Thread与Runnable()的区别:

首先从使用形式来讲,明显使用Runnable实现多线程要比继承Thread类要好,因为可以避免单继承局限

其次,Thread类是Runnable接口的实现类,所以一定覆写了Runnable的run()方法。

不难发现,在多线程的处理上,我们使用了代理设计模式。

实际上在开发之中使用Runnable还有一个特点:使用Runnable实现的多线程的程序类可以更好的描述出程序共享的概念(并不是说Thread不能)

此时 我们使用继承Thread的方法 实现两个人共同卖票的功能

package com.revision.Thread;
//使用Thread类对售票进行模拟
public class SellTickets extends Thread {
    private int ticketnum = 10; //十张票

    @Override
    public void run() {
        while(this.ticketnum >= 1){
            System.out.println("剩余票数:"+ ticketnum--);
        }
    }

    public static void main(String[] args) {
        new SellTickets().start();
         new SellTickets().start();
    }
}

运行结果如图
在这里插入图片描述
本来希望的是这两个线程共同卖10张票 结果变成各自卖各自的。

利用实现Runnable()接口来实现同步卖票功能:

package com.revision.Thread;
//使用Thread类对售票进行模拟
public class SellTickets implements Runnable{
    private int ticketnum = 10; //十张票

    @Override
    public void run() {
        while(this.ticketnum >= 1){
            System.out.println("剩余票数:"+ ticketnum--);
        }
    }

    public static void main(String[] args) {
        SellTickets st = new SellTickets();

        new Thread(st).start();
        new Thread(st).start();

    }
}

运行结果如图:
在这里插入图片描述

因此可以得出结论:
Runnable实现的多线程的程序类可以更好的描述出程序共享的概念

2.4 Callable实现多线程

JDK1.5开始追加了新的开发包:java.uti.concurrent。这个开发包主要是进行高并发编程使用的,包含很多在高并发操作中会使用的类。在这个包里定义有一个新的接口Callable

@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}

Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程

package com.revision.Thread;

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

public class MyCallable implements Callable {

    private int tickets = 10;

    @Override
    public Object call() throws Exception {
        while(this.tickets >= 0){
            System.out.println("剩余票数:" + tickets--);
        }
        return "票卖完了!";
    }

    public static void main(String[] args) throws InterruptedException,
            ExecutionException {
        FutureTask<String> task = new FutureTask<>(new MyCallable());
        new Thread(task).start();
        new Thread(task).start();
        System.out.println(task.get());

    }
}

以上形式主要是为了取得线程的执行结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值