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对象,这样就直接实现了。

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 苹果电脑出现 .DS_Store文件,删除不掉怎么处理?

    苹果电脑出现 .DS_Store文件,删除不掉怎么处理?

  • Oracle Insert分批提交「建议收藏」

    Oracle Insert分批提交「建议收藏」oracle中分批提交insert事务,以防止redo占用太多可以分批提交事务:以下是三种不同的pl/sql体:1、编写一个简单的PL/SQL块来模拟逐行提交的情况,注意观察执行时间。我们的目标是将t_ref表中的数据全部插入到t中。sec@ora10g>settimingonsec@ora10g>DECLARE2BEGIN3FORcurIN(SEL…

  • 什么是异步传输模式和同步传输模式_什么是异步传输模式交换技术

    什么是异步传输模式和同步传输模式_什么是异步传输模式交换技术  分组交换是在“存储——转发”基础上发展起来的一种传输模式。分组交换在线路上采用动态复用技术传送按一定长度分割为许多小段的数据——分组。每个分组标识后,在一条物理线路上采用动态复用的技术,同时传送多个数据分组。这和以太网的碰撞侦测技术有着本质的区别。 ATM是在分组交换基础上发展起来的一种传输模式,在这一模式中,信息被组织成信元,因包含来自某用户信息的各个信元不需要周期性出现,它是区别于其它传

  • 看看行不行「建议收藏」

    看看行不行「建议收藏」支持FreakshareRapidgatorHotfileKeep2shareRyushareFilepostLumfileBitshareFilefactoryExtabitNetloadUploaded.toUl.toCtdisk等主流网盘会员直接高速下载!Ctdisk城通网盘/Dbank华为网盘完全免费!http://wishuhappy.com/[@Ie4Gy

  • 微生物组助手——最易学的扩增子、宏基因组分析流程

    微生物组助手——最易学的扩增子、宏基因组分析流程软件简介MicrobiomeHelper开源软件,方便大家分析微生物组数据。不仅提供了多套扩增子、宏基因组的分析流程方案,同时提供了几十个软件间衔接的脚本,可大大提高使用者分析的效率。文章于2017年发表于mSystems。Github项目主页:https://github.com/LangilleLab/microbiome_helpermicrobiomehelp结合不同组…

  • ubuntu 出现GPG Error的问题[通俗易懂]

    ubuntu 出现GPG Error的问题[通俗易懂]ubuntu系统sudoapt-getupdate错误提示:gpgerrorthepublickeyisnotavailableno_pubkey5523BF*********在我们系统上无法获取publickey,所以需要导入该publickey 解决办法:sudoapt-keyadv–keyserverkeys

    2022年10月13日

发表回复

您的电子邮箱地址不会被公开。

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