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

相关推荐

  • ROC曲线和AUC面积理解[通俗易懂]

    ROC曲线和AUC面积理解[通俗易懂]关注微信公众号【Microstrong】,我现在研究方向是机器学习、深度学习,分享我在学习过程中的读书笔记!一起来学习,一起来交流,一起来进步吧!本文同步更新在我的微信公众号中,公众号文章地址:https://mp.weixin.qq.com/s?__biz=MzI5NDMzMjY1MA==&mid=2247484146&idx=1&sn=963765a3ede231292…

    2022年5月17日
  • Java 通过正则表达式替换字符串

    Java 通过正则表达式替换字符串简介java中提供了两个类来支持正则表达式的操作,分别是java.util.regex下的Pattern类和Matcher类依据Pattern对象做为匹配模式对字符串展开匹配检查,然后Matcher实例在给定的Pattern实例的模式控制下进行字符串的匹配,在实际的开发中,为了方便我们很少直接使用Pattern类或Matcher类,而是使用String类下的方法进行替换。…

    2022年5月16日
  • IP地址分类详解

    IP地址分类详解一、IP地址简介IP,即网际协议(InternetProtocol),或称互联网协议,是用于报文交换网络的一种面向数据的协议。IP是在TCP/IP协议中网络层的主要协议,任务是仅仅根据源主机和目的主机的地址传送数据。为此目的,IP定义了寻址方法和数据报的封装结构,即IP地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以

    2022年6月9日
  • dsp指令ixh_C24XX系列DSP移位指令总结[通俗易懂]

    dsp指令ixh_C24XX系列DSP移位指令总结[通俗易懂]C24XX系列DSP移位指令总结徐丽红王佰营TI公司C24XX系列DSP的移位指令很有特色而且效率很高;一般的移位功能不用专门的指令实现而是作为其他指令中的一个功能给出,并且移位并不占用CPU额外时间。以下整理出了DSP常用的移位指令:一、两类移位指令1>显性移位指令,移位次数由指令直接给出:1add—sub←0—162and—or—xor←#L3lacc←0—164sach—sacl←…

    2022年5月18日
  • 怎么查看linux系统内核版本_linux服务器版本

    怎么查看linux系统内核版本_linux服务器版本linux下如何查看系统和内核版本(2011-04-1117:35:16)标签:linuxversion杂谈1.查看内核版本命令:1)[root@q1test01~]#cat/proc/versionLinuxversion2.6.9-22.ELsmp(bhcompile@crowe.devel.redhat.com)(gccversion3.4.420050721(Re…

    2022年10月9日
  • org.apache.jasper.JasperException: An exception occurred processing JSP page

    JPivothadanerror…org.apache.jasper.JasperException:AnexceptionoccurredprocessingJSPpage/testpage.jspatline4441:42:43:44: 45: 46: 47: Stacktrace:org.apache.jasper.JasperEx

    2022年4月9日

发表回复

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

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