Java学习之多线程篇

0x00前言在一个工具开发中,如果该工具需要不断的去执行同一个动作或者是请求的话,使用单线程是非常慢。还是拿一个目录扫描器来举例子,比如我们需要开发一个目录扫描器,我们的字典里有10000个字典,

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

0x00 前言

在一个工具开发中,如果该工具需要不断的去执行同一个动作或者是请求的话,使用单线程是非常慢。还是拿一个目录扫描器来举例子,比如我们需要开发一个目录扫描器,我们的字典里有10000个字典,,只有一个线程去发起http的请求,这样的速度是非常慢的,但是如果我们用到多线程,4个线程,每个线程请求2500个字典,那么我们花费的时间就可以缩短4倍。

0x01 多线程概念

线程与进程

在了解多线程前,首先要清楚多线程和多进程的区别。

进程:一个程序运行在一个指定内存块当中。一个程序可以同时运行多个进程。

线程:线程是进程里面的一个执行单元,负责当前程序的执行,一个进程里面至少有一个线程。

一个程序运行运行,至少有一个进程,而一个进程可以开多个线程。在我们开发中,一般是使用多线程来开发。

线程调度

分时调度:使用线程轮流使用cpu使用权,平均分配每个线程占用cpu时间。

抢占式调度:有限让优先级高的线程使用cpu,,如果线程的优先级同等,就会随机选择一个线程进行执行,java当中默认是抢占式线程调度。

0x02 多线程编程

在java里面可以使用Thread创建多线程程序,所有的线程对象必须是Thread类或者是其子类的实例。

首先先来看看他的构造方法:

public Thread() :分配一个新的线程对象。
public Thread(String name) :分配一个指定名字的新的线程对象。
public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字

使用方式:

1.定义一个子类继承Thread,然后对run方法进行重写,run方法的方法体代表线程需要完成的任务。
2.实例化该子类对象,然后调用start方法

public class Demo11 extends Thread{
    @Override
    public void run() {
        System.out.println("我是子线程");
    }
}

创建thread的子类,并对run方法进行重写。

public static void main(String[] args)  {

        Demo11 thread = new Demo11();
        thread.start();
        System.out.println("我是主线程");
    }

实例化实现类对象,然后使用start进行子线程的启动。

Runnable创建多线程

通过实现Runable接口,使该类有了多线程的特征。run()方法里面是多线程里面需要执行的代码。Thread实际上也是实现了runnable接口里面的类。
在所有多线程里面其实都是Thread这个类来操控线程。

使用步骤:

首先创建一个Runnable的实现类,然后重写run方法,使用Thread类实例化对象,将runnable实例化的对象传递进去,使用thread的实例化对象调用start方法进行创建线程。

代码:

runnable实现类:

public class Demo11 implements Runnable{
    @Override
    public void run() {
        System.out.println("我是子线程");
    }
}

main方法代码:

public static void main(String[] args)  {

        Demo11 run = new Demo11();
        Thread thread = new Thread(run);
        thread.start();
        System.out.println("我是主线程");
    }

这两种方式的都可以实现多线程,但是如果使用第一种方法,,不适合资源的共享,而runable这种方式的话,容易实现资源的共享。

Runnable接口的优势:

1. 适合多个相同的程序代码的线程去共享同一个资源。
2. 可以避免java中的单继承的局限性。
3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

匿名内部类创建多线程

我们在每次创建线程,需要创建实现类,然后在实例化实现类,再对其进行调用。而一个thread的strart方法只能调用一次,那么我们就可以使用匿名内部类对他进行定义。

public static void main(String[] args)  {

        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("我是子线程");
            }
        };
        new Thread(r).start();

        System.out.println("我是主线程");
    }

0x03 线程安全

如果有多个线程同时在运行,并且是对某一个变量进行操作的话,那么这时候就会产生一些新的问题。
咱们还是拿一个目录扫描器来举例子,如果我们的字典里面有100个字典,需要开多个线程去扫描,那么这时候我们,如果直接让他去发起请求,那么这几个线程读取的都是同样的一个字典并且读取了5次,达不到多线程起到分工合作的一个效果。

那么这时候我们就可以使用到同步机制或者说线程锁解决掉这个问题。

同步代码块

同步代码块:synchronized关键字可以用于方法中的某个区块中,表示对这个区块的资源实行互斥。

格式:

synchronized(同步锁){
需要同步操作的代码
}

同步锁其实也只是一个概念,在对象上标记一个锁。

锁的对象可以是任意类型,但个线程对象要使用同一把锁

实现接口:

package cn.itcast;

public class Demo11 implements Runnable{
    private int num = 100;
    private boolean flag = true;
    Object obj = new Object();

    @Override
    public void run() {
        while (flag){
            synchronized (obj){
                if (num==0){
                    flag = false;
                }else {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("我是子线程"+Thread.currentThread()+"数值"+num--);
                }

                }
            }
        }

    }


main方法:

public class DemoMain {
    public static void main(String[] args) {
        Demo11 r = new Demo11();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();

    }
}

Lock同步锁

Lock机制比synchronized代码块方法更广泛。

常用方法:

public void lock()  : 获取锁
public void unlock(): 释放锁

代码实例:

package cn.itcast;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo11 implements Runnable {
    private int num = 100;
    private boolean flag = true;
    Lock lock = new ReentrantLock();



    @Override
    public void run() {

        while (flag) {
            lock.lock();
            if (num == 0) {
                flag = false;
            } else {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("我是子线程" + Thread.currentThread() + "数值" + num--);
            }
            lock.unlock();


        }
    }
}

mian方法:

public class DemoMain {
    public static void main(String[] args) {
        Demo11 r = new Demo11();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();

    }
}

0x04 结尾

多线程会在我们开发工具常用到,一些工具需要高并发提高效率,不然效率很低。后面也可以开发一些可以自定义线程的程序,用户输入多少个线程,可以直接使用匿名内部类new 多少个thread对象,这样就直接实现了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119952.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java简单酒店管理系统_javaweb酒店管理系统

    java简单酒店管理系统_javaweb酒店管理系统编写Java程序实现小型酒店管理系统。为某个酒店编写程序:酒店管理系统,模拟订房、退房、打印所有房间状态等功能。1、该系统的用户是:酒店前台。2、酒店使用一个二维数组来模拟。“Room[][]rooms;”3、酒店中的每一个房间应该是一个java对象:Room4、每一个房间Room应该有:房间编号、房间类型、房间是否空闲.5、系统应该对外提供的功能:可以预定房间:用户输入房间编号,订房。可以退房:用户输入房间编号,退房。可以查看所有房间的状态:用户输入某个指令应该可以查看所有房间状态。

    2022年9月25日
    0
  • java递归和迭代的区别

    java递归和迭代的区别出现栈的溢出.而迭代不会!  递归的基本概念:程序调用自身的编程技巧称为递归,是函数自己调用自己.一个函数在其定义中直接或间接调用自身的一种方法,它通常把一个大型的复杂的问题转化为一个与原问题相似的规模较小的问题来解决,可以极大的减少代码量.递归的能力在于用有限的语句来定义对象的无限集合.使用递归要注意的有两点:1)递归就是在过程或函数里面调用自身;2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 递归分为两个阶段:1)递推:把复杂的问题的求解推到比原问

    2022年5月5日
    45
  • Ubuntu20.04上安装Edge「建议收藏」

    Ubuntu20.04上安装Edge「建议收藏」原文地址:HowtoInstallMicrosoftEdgeBrowseronUbuntu20.04|Linuxizehttps://linuxize.com/post/how-to-install-edge-browser-on-ubuntu-20-04/1.更新源sudoaptupdatesudoaptinstallsoftware-properties-commonapt-transport-httpswget2.导入MicrosoftGPGKey

    2022年7月21日
    15
  • 如何求原根_求模47的所有原根

    如何求原根_求模47的所有原根说这种最好就是举个例子比如说求81的所有原根 先说欧拉函数通式:通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1,p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数(小于等于1)就是1本身)。(注意:每种质因数只一个。比如12=2*2*3那么φ(12)=12*(1-1/2)*(1-1/…

    2025年7月5日
    0
  • nv121_nvl2函数用法

    nv121_nvl2函数用法#include#include#include#include#includetypedefunsignedcharuint8_t; /**  *@paramsrcinputnv12rawdataarray  *@paramdstoutputnv12rawdataresult,  *thememor

    2022年9月24日
    0
  • 执行pip 命令出现Could not install packages due to an EnvironmentError错误的解决办法「建议收藏」

    执行pip 命令出现Could not install packages due to an EnvironmentError错误的解决办法「建议收藏」今天想安装一个pyspider,但是却出现了下图的错误因为环境的错误导致的原因,嗯…….搜了一下,只需把命令改为pipinstall–userpyspider就可以了。网上的回答是直接这样就行了,但是我的却出现了另一个问题。这个包是安装成功了,但是调用时输入pyspiderall,却返回了pyspider不是内部或外部命令的提示,注意看安装成功之前有几行…

    2022年9月13日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号