首页 > 编程语言 >Java中的多线程

Java中的多线程

时间:2023-07-07 12:22:49浏览次数:41  
标签:Java Thread void 线程 new 多线程 方法 public

1. 线程实现

1.1 线程创建(三种方法)

  1. Java下载图片的方法:通过FileUtils.copyURLToFile方法
  2. 获取线程名字Thread.currentThread.getName()
class WebDownloader {
    //下载方法
    public void downloader(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

继承Thread类

继承后实现run方法,在main方法中可以new新对象直接调用start方法。

实现Runnable接口 (最重要)

实现run方法后,在main方法中new了新对象,还要将其传入new Thread中,才可以调用start方法。
还可以在newThread传入对象的同时,传入一个字符串表示线程名字。

实现Callable接口

实现Callable接口<Boolean>有返回值,创建目标对象,创建执行服务,提交执行代替.start,获取结果bool,关闭服务。

类 c = new C();

  1. 创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);
  2. 提交执行 Future<Boolean> r=ser.submit(c)
  3. 获取结果 boolean res= r.get();
  4. 关闭服务 ser.shutdownNow()

1.2 静态代理

真实对象和代理对象都实现同一个接口。
代理对象做真实对象做不了的事,让真实对象专注做自己的事。

// 线程中使用的就是代理模式
public class Demo8_StaticProxy {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("我爱你")).start();
        new WeddingCompany(new You()).happyMarry();
    }
}

1.3 Lamda表达式

对于实现函数式接口的类可以被Lamda表达式替代。
函数式接口定义

包含唯一一个抽象方法。
new 接口名({函数方法}); 等价于
(int a,int b) ->{
sout();
}

  1. 接口实现只有一行代码时可以省略{}
  2. 可以省略参数类型 ,要省略就必须全省略
  3. 多个参数必须有()

2.线程的状态

2.1 状态转换

new -》创建状态
.start -》就绪状态
.sleep /wait -》阻塞状态

2.2 线程方法

方法 说明
setPriority(int newPriority) 更改线程优先级
static void sleep(long millis) 指定毫秒休眠
void join 等待该线程终止
static void yield() 暂停当前 正在执行的线程对象,并执行其他线程
void interrupt() 中断线程,不推荐~!!
boolean isAlive() 检测是否存活

停止线程 自己写stop

不推荐stop/destroy等JDK不建议的方法。
不建议使用死循环
建议正常停止,使用标志位。

image

线程休眠 Thread.sleep(int mills)

  1. sleep时间到达后进入就绪状态
  2. 可以模拟网络延时,倒计时
  3. 每一个对象都有一把锁,Sleep不会释放锁
//模拟时钟
public class Recount implements Runnable{
    @Override
    public void run() {
        Date date = new Date(System.currentTimeMillis());
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(new SimpleDateFormat("YY:MM:dd:HH:mm:ss").format(date));
            date=new Date(System.currentTimeMillis());
        }
    }

    public static void main(String[] args) {
        Recount recount = new Recount();
        new Thread(recount).start();
    }
}

线程礼让 Thread.yield()

  1. 让当前线程暂停,回到就绪状态。
  2. CPU重新调度,所以礼让不一定成功。

线程插队 对象thread.join()

  1. 其他线程阻塞等待对象线程执行完毕
  2. 由其他线程 使用对象线程引用.join()。相当于某线程让别的线程先强制执行。
public class Jointest implements Runnable{
    @Override
    public void run() {
        for (int i=0;i<500;i++) {
            System.out.println("vip线程来啦"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Jointest jointest = new Jointest();
        Thread vip =new Thread(jointest);
        vip.start();
        for (int i = 0; i < 200; i++) {
            if(i==100) {
                vip.join();
            }
            System.out.println("我是主线程"+i);
        }
    }
}

观察线程状态 Thread.State

  1. NEW:刚new出来的线程
  2. RUNNABLE:执行了statrt,在虚拟机中执行的线程
  3. BLOCKED:被阻塞的线程
  4. WAITING:正在等待另一个线程执行特定动作的
  5. TIMED_WAITING:正在等待到指定时间的线程。
  6. TERMINATED:已推出的线程。
    Thread.State state = thread.getState()

线程优先级 thread.setPriority(int x)

  1. 默认优先级是5
  2. 范围1-10
  3. 常量 Thread.Max_PRIORITY /MIN_PRIORITY

守护线程 thread.setDaemon(boolean )

  1. 线程分为 用户线程守护线程
  2. 虚拟机确保用户线程执行完毕,不用等待守护线程执行完毕
  3. 常见的守护线程有 后台记录操作日志,监控内存,垃圾回收
  4. 设置用户线程为守护线程: thread.setDaemon(true)

3. 线程同步

多线程对同一对象访问,需要线程同步。这是一种等待机制,多个需要访问该对象的线程进入对象的等待池形成队列。
同步的形成条件: 队列+锁

3.1 不安全的情况

由于线程在自己内存处理导致

  1. 购票
  2. 取钱
  3. 集合 (多线程操作同一块。)

3.2 隐式锁 Synchronized

同步方法

在方法中加入关键字,相当于锁this这个对象本身。方法一旦执行,就独占锁直到方法返回,后面被阻塞的线程才能获得锁。

同步代码块 Synchronized(OBJ) {}

OBJ称为同步监视器,将变量/共享资源作为同步监视器可以达到同步的目的。
在原有代码上外套{}即可

JUC安全集合类型扩充

java.util.concurrent包中的
CopyOnWriteArrayList集合是安全的。底层有votilaite关键字。

3.3 显示锁 Lock

  1. concurrent.locks.Lock是一个接口,线程开始访问共享资源应先获取Lock对象。
  2. Lock的实现类 可重入锁ReentrantLock,可以显式加锁解锁。
    image

4. 线程通信

4.1 通信方法

都是Object类的方法,只能在同步方法或同步代码块中使用,否则会抛出异常。

方法名 作用
wait() 线程释放锁并等待
wait(long timeout) 指定等待的毫秒数
notify() 唤醒一个处于等待状态的线程
notifyAll() 唤醒同一个对象上所有调用wait()方法的线程。

生产者消费者举例

  1. 容器方法
    消费者和生产者各自定义缓冲区,调用容器的方法;缓冲区定义容器大小,定义容器增减方法。
  2. 信号灯法
    消费者和生产者各自定义传递的数据类,调用容器方法。缓冲区通过自定义的flag来控制。
public class Demo33_ThreadPC {
    public static void main(String[] args) {
        SynContainer synContainer = new SynContainer();
        new Producer(synContainer).start();
        new Consumer(synContainer).start();
    }
}

//生产者
class Producer extends Thread {
    //容缓冲区
    SynContainer container;

    public Producer(SynContainer container) {
        this.container = container;
    }

    //生产
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            container.push(new Product(i));
            System.out.println("生产了" + i + "件产品");
        }
    }
}

//消费者
class Consumer extends Thread {
    //容缓冲区
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }

    //消费
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了-->" + container.pop().id + "件产品");
        }
    }
}

//产品
class Product {
    int id;//产品编号

    public Product(int id) {
        this.id = id;
    }
}

//缓冲区
class SynContainer {
    //需要一个容器大小
    Product[] products = new Product[10];
    //容器计数器
    int count = 0;

    //生产者放入产品
    public synchronized void push(Product product) {
        //如果容器满了,需要等待消费者消费
        /*如果是if的话,假如消费者1消费了最后一个,这是index变成0此时释放锁被消费者2拿到而不是生产者拿到,这时消费者的wait是在if里所以它就直接去消费index-1下标越界,如果是while就会再去判断一下index得值是不是变成0了*/
        while (count == products.length) {
            //通知消费者消费,等待生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果没有满,需要丢入产品
        products[count] = product;
        count++;
        //通知消费者消费
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Product pop() {
        //判断是否能消费
        while (count <= 0) {
            //等待生产者生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Product product = products[count];
        //吃完了 通知生产者生产
        this.notifyAll();
        return product;
    }
}

标签:Java,Thread,void,线程,new,多线程,方法,public
From: https://www.cnblogs.com/its1440/p/17526015.html

相关文章

  • Java true和false类型如何取反 这个问题怎么解决?
    Javatrue和false类型如何取反在Java中,true和false是布尔类型的取值。布尔类型只有两个取值:true和false。它通常用于判断和控制程序的流程。在某些情况下,我们需要对布尔类型进行取反操作。下面将介绍如何在Java中对布尔类型进行取反,并给出一个具体问题的解决方案。布尔类型的取反......
  • 如何实现Java postgresql 开启事务的具体操作步骤
    JavaPostgreSQL开启事务在Java应用程序中使用PostgreSQL数据库时,事务管理是一个非常重要的概念。事务是一组数据库操作的集合,要么全部成功,要么全部失败。通过使用事务,可以确保数据的一致性和完整性。本文将介绍如何在Java中使用PostgreSQL开启事务,并提供相应的代码示例。什么是......
  • 如何实现Java ora-01861:文字与格式字符串不匹配的具体操作步骤
    Java异常解析:ora-01861:文字与格式字符串不匹配当在Java程序中使用数据库操作时,可能会遇到ora-01861:文字与格式字符串不匹配异常。这个异常是由于将一个与格式化字符串不匹配的数据插入到数据库中引起的。在本文中,我们将详细介绍这个异常的原因、解决方法以及如何避免它的发......
  • 如何实现Java mqtt 客户端,收到自己发出消息的具体操作步骤
    实现JavaMQTT客户端收到自己发出的消息介绍在本文中,我将教会你如何使用Java实现一个MQTT(MessageQueuingTelemetryTransport)客户端,以接收自己发出的消息。MQTT是一个轻量级的消息协议,广泛应用于物联网和实时通信领域。我们将使用EclipsePaho库来实现这个功能。整体流程下面......
  • Java中NIO为什么需要buffer
    在Java的NIO(NewInput/Output)中,Buffer是一个关键概念,用于高效地处理数据。以下是一些JavaNIO中需要Buffer的原因:内存管理:Buffer提供了一种更有效的内存管理方式。它可以在堆内存或直接内存中创建一个固定大小的内存区域,用于暂存数据。这样可以避免频繁的内存分配和释放操作,提......
  • java 关于数据库外键
    查询性能:当查询涉及到外键关系时,数据库需要进行额外的操作来验证关联关系的完整性,这可能会导致查询速度变慢。特别是在大型数据库系统中,外键的验证操作可能会消耗较多的计算资源和时间。更新性能:当更新外键相关的数据时,数据库需要确保更新操作不会破坏关联关系的完整性。这可......
  • java BufferedImage怎么转byte[]?
    一.为什么要将BufferedImage转为byte数组?在传输中,图片是不能直接传的,因此需要把图片变为字节数组,然后传输比较方便。而字节数组变成BufferedImage能够还原图像。参考1:https://blog.csdn.net/weixin_39958559/article/details/114788932参考2:https://blog.csdn.net/itigoitie/......
  • Java中Socket通信的一个注意点
    在使用socket通信时,我们可能会注意到这样一个现象:客户端通过新建的Socket对象获取输入流,读取服务器端传输给自己的内容。Socketsocket=newSocket("127.0.0.1",8086);InputStreamis=socket.getInputStream();is.read()服务器端通过accept方法获取Socket对象,然后再......
  • Java语言语法语义分析器设计与实现
    Java语言词法分析器的设计与实现一.实验目的1.强化对系统软件综合工程实现能力、规划能力的训练;2.加强对词法分析原理、方法和基本实现技术的理解;二.实验内容用C语言(或C++)作为宿主语言完成:     其中具体要求:    1.使用DFA实现词法分析器的设计;    2.实现对Java源程......
  • Java 构造器
    Java构造器1.构造器构造器也叫构造方法,是用来完成对象的初始化。构造器的定义:构造器的定义:[访问修饰符]方法名(形参),构造器与方法不同,并没有返回值,也不能写void,访问修饰符可以是不同的,方法名要与本类的类名相同构造器的调用是由系统在创建对象的时候自动初始化对象。构......