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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python编程100例_python进阶路线图

    python编程100例_python进阶路线图异常模块下面介绍python常用的异常模块AttributeError异常AttributeError试图访问一个类中不存在的成员(包括:成员变量、属性和成员方法)而引发的异常Attribut

    2022年7月28日
    0
  • ActiveMQ简介与安装

    1.ActiveMQ简介ActiveMQ是一种开源的,实现了JMS1.1规范的,面向消息(MOM)的中间件,为应用程序提供高效的、可扩展的、稳定的和安全的企业级消息通信。ActiveMQ使用Apa

    2021年12月28日
    37
  • Docker安装RabbitMQ教程「建议收藏」

    Docker安装RabbitMQ教程「建议收藏」本章教程介绍如何利用Docker快速搭建RabbitMQ环境。目录一、拉取镜像二、运行容器三、访问测试一、拉取镜像dockerpullrabbitmq:3.7.7-management二、运行容器dockerrun-d–namerabbitmq3.7.7-p5672:5672-p15672:15672-v`pwd`/data:/var/lib/rabbitmq–hostnamemyRabbit-eRABBITMQ_DEFAUL..

    2022年5月23日
    33
  • redis分布式锁原理面试(数据库索引用的什么数据结构)

    业务背景:后台定时任务刷新Redis的数据到数据库中,有多台机器开启了此定时同步的任务,但是需要其中一台工作,其他的作为备用,提高可用性。使用Redis分布式锁进行限制,拿到锁的机器去执行具体业务,拿不到锁的继续轮询。分布式锁原理分布式锁:当多个进程不在同一个系统中,多个进程共同竞争同一个资源,用分布式锁控制多个进程对资源的互斥访问。采用Redis服务器存储锁信息(即SET一个Key表示已加锁),可以实现多进程的并发读锁的状态,如果没有锁,则只允许一个进程加锁。Redis分布式锁实现的关键点:

    2022年4月15日
    75
  • clion2021激活码(注册激活)

    (clion2021激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~MLZPB5EL5Q-eyJsaWNlbnNlSWQiOi…

    2022年3月20日
    85
  • 第三单元分支结构

    第三单元分支结构

    2021年9月28日
    52

发表回复

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

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