首页 > 编程语言 >java多线程

java多线程

时间:2023-07-30 14:12:09浏览次数:40  
标签:java Thread util 线程 new 多线程 public

1、什么是JUC

  1. 官方文档+源码

    ​ 面试高频问

    java.util

    java.util.concurrent

    java.util.concurrent.atomic

    java.util.concurrent.locks

​ java,util 工具包、包、分类

业务:普通的线程代码 Thread

Runnable 没有返回值

2、线程和进程

线程和进程 如果不能用一句话说出来的技术就是不扎实

进程:就是一个程序 一个程序的集合

​ 一个进程往往可以有多个线程至少包含一个

java 默认高就有两个线程 main 、GC:垃圾回收

线程:开了一个java 有main线程 GC线程

对应java而言:: Thread、Runnable、Callable

java真的可以开线程吗?? 不可以

    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
	// 本地方法,底层的C++,  java无法操作硬件
    private native void start0();

并发、并行

并发编程:并发 、并行

并发 (多线程操作同一个资源) 充分利用cpu的资源

  • CPU 一核 模拟出来多条线程,天下武功为快不破 快速交替模拟并行(宏观上并行微观上窜行)

并行 (多个人一起走)

  • CPU多核 多个线程可以同时进行;线程池

    package com.lmq;
    
    /**
     * @author 羡鱼
     * @version 1.0
     * @date 2023/7/29 17:05
     */
    public class JucTest {
        public static void main(String[] args) {
            // 获取cpu的核数
            System.out.println(Runtime.getRuntime().availableProcessors());    }
    }
    
    

所有公司都看中

线程有几个状态

public enum State {

         // 新生
        NEW,
         // 运行
        RUNNABLE,
		// 阻塞
        BLOCKED,
		// 等待  一直等
        WAITING,
		// 超时等待
        TIMED_WAITING,

    	//	终止
        TERMINATED;
    }

wait/sleep 区别

1、来自不同的类

wait =>Object

sleep => Thread

2、关于锁的释放

wait 会释放锁 sleep睡觉了,抱着锁睡觉了,不会释放!

3、使用范围是不同的

wait: 必须在同步代码块中使用

sleep 可以任何地方睡觉

4、是否要捕获异常

wait 要捕获异常

sleep 必须捕获异常

3、Lock锁(重点)

传统Synchronized 和 Lock 区别

1、 Synchronized 内置的JAVA关键字 Lock 是一个java类

2、 Synchronized 无法判断获取锁的状态Lock可以

3、 Synchronized 会自动释放锁Lock 必须手动释放锁 ,不释放锁就死锁

4、 Synchronized 线程1(获得锁,阻塞了) 线程2(一直等待);Lock 锁就不一定等下去

5、 Synchronized 可重入锁不可中断,非公平;Lock 可以重锁,可以判断 锁, 非公平(可以自己设置);

6、 Synchronized 适合锁少量的同步代码, Lock 适合锁大量的同步代码

// synchronized 本质 : 队列  锁

Synchronized wait

公平锁 先来后到

非公平锁 可以插队(默认)

锁是什么 如何判断锁的是谁

4、生产者和消费者的问题

面试常问

单例模式 排序算法 生产者消费者 死锁

生产者消费者

package com.lmq.pc;

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/29 18:12
 * <p>
 * 线程之间的通讯  生产者 消费者  等待幻想  通知唤醒
 * 线程交替执行  A B 操作同一个变量  num = 0
 * A num=1
 * B num-1
 */
public class A {
    public static void main(String[] args) {
        Data data = new Data();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "B").start();
    }
}


// 判断  等待   业务   通知
class Data {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        if (number != 0) {
            this.wait();
        }
        number++;
        // 通知其他线程
        this.notify();
        System.out.println(Thread.currentThread().getName() + "=>" + number);
    }

    public synchronized void decrement() throws InterruptedException {
        if (number == 0) {
            this.wait();
        }
        number--;
        this.notify();
        System.out.println(Thread.currentThread().getName() + "=>" + number);
    }
}

使用if判断会出现虚假唤醒 使用while

package com.lmq.pc;

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/29 18:12
 * <p>
 * 线程之间的通讯  生产者 消费者  等待幻想  通知唤醒
 * 线程交替执行  A B 操作同一个变量  num = 0
 * A num=1
 * B num-1
 */
public class A {
    public static void main(String[] args) {
        Data data = new Data();

        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "C").start();
    }
}


// 判断  等待   业务   通知
class Data {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        while (number != 0) {
            this.wait();
        }
        number++;
        // 通知其他线程
        this.notify();
        System.out.println(Thread.currentThread().getName() + "=>" + number);
    }

    public synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            this.wait();
        }
        number--;
        this.notify();
        System.out.println(Thread.currentThread().getName() + "=>" + number);
    }
}

原来的 synchronized wait notify

juc的 (Lock)Lock ()await signal

juc 版本生产者消费者

Lock 找到 Condi

上锁 等待 通知 解锁

package com.lmq.pc;

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

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/29 18:48
 */
public class B {
    public static void main(String[] args) {
        Data2 data = new Data2();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "A").start();


        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "C").start();


        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }, "D").start();
    }
}

class Data2 {
    private int number = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public  void increment() throws InterruptedException {

        lock.lock();
        try {
            while (number != 0) {
                condition.await();
            }

            number++;
            // 通知其他线程
            condition.signalAll();
            System.out.println(Thread.currentThread().getName() + "=>" + number);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public  void decrement()   {
        lock.lock();
        try {
            while (number == 0) {
                condition.await();
            }
            number--;
            condition.signalAll();
            System.out.println(Thread.currentThread().getName() + "=>" + number);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Lock 可以精准唤醒进程

可以设置多个监视器

5、8锁现象

如何判断锁的是谁!

  • s锁就是关于锁的8个问题
    1. 标准情况下 连个线程先打印 发短信还是打电话 1、发短信 2、打电话 都是phone 调用所以先发短信 后 打电话
    1. 发短信方法延迟四秒两个线程先打印? 发短信还是先
    1. 加入普通方法后先发短信还是普通方法? 执行普通方法
    1. 两个对象 两个同步方法 先发短信还是先打电话? 先打电话 对象不同 phone2 和phone1 各有一把锁
    1. 增加两个静态方法,只有一个对象,先打印 发短信 还是打电话? 发短信static 锁的是类 全局唯一
    1. 两个对象!增加两个静态的同步方法 先打印发短信还是打电话? 发短信 static 锁的是class class只有一个
    1. 一个是静态同步方法一个是普通同步方法, 一个一下先发育发短信还是打电话? 打电话
    1. 一个是静态同步方法一个是普通同步方法
package com.lmq.lock8;

import java.util.concurrent.TimeUnit;

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/29 20:28
 *
 *
 *
 * s锁就是关于锁的8个问题
 * 1. 标准情况下 连个线程先打印 发短信还是打电话  1、发短信 2、打电话  都是phone 调用所以先发短信 后 打电话
 * 2. 发短信方法延迟四秒两个线程先打印? 发短信还是先
 * 3. 加入普通方法后先发短信还是普通方法?     执行普通方法
 * 4. 两个对象 两个同步方法  先发短信还是先打电话?   先打电话 对象不同 phone2 和phone1 各有一把锁
 * 5. 增加两个静态方法,只有一个对象,先打印 发短信 还是打电话?  发短信static 锁的是类 全局唯一
 * 6. 两个对象!增加两个静态的同步方法 先打印发短信还是打电话?    发短信 static 锁的是class class只有一个
 * 7. 一个是静态同步方法一个是普通同步方法, 一个一下先发育发短信还是打电话?  打电话
 * 8. 一个是静态同步方法一个是普通同步方法
 *
 */
public class Text1 {

    public static void main(String[] args) throws InterruptedException {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(phone1::sendSms,"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(phone2::call,"B").start();

    }
}


class Phone{

    // synchronized  锁的对象是方法的调用者(在上面可以看到锁的phone phone调用的方法)!  两个方法用的同一个锁 谁先拿到谁先执行
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("sendSms");
    }
    public synchronized void call(){
        System.out.println("call");
    }

    public void hello() {
        System.out.println("hello");
    }
}

小结

new this 具体的一个手机

static Class 唯一的一个模版

6、集合类不安全

并发下 集合就不安全

package com.lmq.unsafe;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/29 21:13
 */

// java.util.ConcurrentModificationException
public class ListTest1 {
    public  static void main(String[] args) {

        // 并发下 ArrayList 不安全
        // 解决方案
        // 1.  在ArrayList 前面就已经有 Vector()  在java 1.0 就有了
        // 2.  Collections.synchronizedList(new ArrayList<>())
        // 3.  new CopyOnWriteArrayList<>();  JUC方案
        //   CopyOnWrite 写入时复制  COW 计算机程序设计领域的一种优化策略
        //   多线程调用的时候 List 读取的时候 固定的写入(覆盖)
        //  在写入的时候避免覆盖  造成数据问题
        //  在写入的时候避免覆盖 造成数据问题
        // 读写分离


        // CopyOnWriteArrayList<>() 比 Vector()  强在哪里  只要用synchronized效率就比lock锁底

//        ArrayList<String> list = new ArrayList<>();
//        List<String> list = Collections.synchronizedList(new ArrayList<>()) ;
        List<String> list = new CopyOnWriteArrayList<>();

        for (int i=0;i<=10;i++){
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

学习方法推荐 1.先学会用 2.货比三家寻找解决方案 3.分析源码

Set 方法不安全

package com.lmq.unsafe;

import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/30 10:14
 */
public class SetTest {
    public static void main(String[] args) {
//        HashSet<String> set = new HashSet<>();
        //  java.util.ConcurrentModificationException
//       方案一 Set<Object> set = Collections.synchronizedSet(new HashSet<>());
//      方案二  Set<String> set = new CopyOnWriteArraySet<>();
        Set<String> set = new CopyOnWriteArraySet<>();


        for (int i =1;i<=10;i++){
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

hashSet 底层是什么?

就是HashMap

7、Map 不安全

package com.lmq.unsafe;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/30 10:50
 */
public class MapTest {
    public static void main(String[] args) {
        // 什么是map  是怎么用的  等价于什么
        // 不用  工作中不用HashMap
        // 默认等价于什么  new HashMap<>(16,0.75)
//        Map<String, String> map = new HashMap<>();
//        Map map = Collections.synchronizedMap(new HashMap<String,String>());
        Map<String, String> map = new ConcurrentHashMap<>();
        // 加载因子  初始化容量

        for (int i = 0; i <= 30; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }

    }
}

7、 Callable (简单)

Thread 只能接受 Runable

  • new thread(new Runnable()).start();
  • new Thread(new FutureTask()).start();
  • 两个对等 FutureTask是Runnable的实现类
  • new Thread(new FutureTask()).start();
package com.lmq.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author 羡鱼
 * @version 1.0
 * @date 2023/7/30 11:38
 */
public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // new thread(new Runnable()).start();
        // new Thread(new FutureTask<V>()).start();
        // 两个对等 FutureTask是Runnable的实现类
//        new Thread(new FutureTask<V>()).start();


        new Thread().start();
        MyThread thread = new MyThread();

        FutureTask futureTask = new FutureTask(thread);

        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start(); // 细节 结果有缓存 只打印一个hello   结果可能需要等待 会阻塞
        Object o = futureTask.get(); // 获取Callable 返回值
        System.out.println(o);
    }
}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("hello");
        return 1024;
    }
}

标签:java,Thread,util,线程,new,多线程,public
From: https://www.cnblogs.com/lmq886/p/17591370.html

相关文章

  • Java之Stream流综合案例
    Java之Stream流综合案例需求:某个公司的开发部门,分为开发一部和二部,现在需要进行年中数据结算。分析:员工信息至少包含了(名称、性别、工资、奖金、处罚记录)开发一部有4个员工,开发二部有5个员工。分别筛选出2个部门的最高工资的员工信息,封装成优秀员工对象。分别统......
  • Java中过滤出ListA和ListB中字段相同的集合
    Java中过滤出ListA和ListB中age字段相同的User集合在Java中,List是一种常见的集合类型,它可以用来存储一组有序的数据。而对于List中存储的对象类型,我们可以使用泛型来进行限定。假设我们现在有两个List集合,分别为ListA和ListB,它们都存储了一些User对象。现在我们需要从这两个集合......
  • JavaScript、ECMA、CommonJs、NodeJS、TypeScript的关系
    返回JavaScript发布时间:1995发布公司:Netscape(网景)它是一种高级的解释型编程语言,简称JS它最初的设计目标是改善网页的用户体验。......
  • 设计模式-迭代器模式在Java中使用示例
    场景为开发一套销售管理系统,在对该系统进行分析和设计时,发现经常需要对系统中的商品数据、客户数据等进行遍历,为了复用这些遍历代码,开发人员设计了一个抽象的数据集合类AbstractObjectList,而将存储商品和客户等数据的类作为其子类AbstractObjectList类的子类ProductList和Custo......
  • Java的readBytes是怎么实现的?
    1.前言众所周知,Java是一门跨平台语言,针对不同的操作系统有不同的实现。本文从一个非常简单的api调用来看看Java具体是怎么做的.2.源码分析从FileInputStream.java中看到readBytes最后是native调用/***Readsasubarrayasasequenceofbytes.*@parambtheda......
  • 【Java】《2小时搞定多线程》个人笔记
    简介基于慕课网站上的一个一元钱课程《2小时搞定多线程》的个人笔记。线程的起源我们先来看看网络中关于线程起源的说明,理解线程的来龙去脉对于掌握多线程有一定帮助。此部分内容整理自下面两篇网络博客:#线程是什么#线程的起源线程的起源与计算机的发展息息相关。早期的计算机系......
  • VarHandle:Java9中保证变量读写可见性、有序性、原子性利器
    文章目录一、什么是VarHandle0、JMM1、jdk9之前无锁技术的实现二、VarHandle使用1、VarHandle快速上手2、VarHandle常用方法3、实战案例1:解决可见性(比volatile轻量)4、实战案例2:解决指令重排序(比volatile轻量)(1)案例分析:partialordering(2)案例分析:totalordering一、什么是VarHand......
  • Dubbo(一)_Java_SPI
    什么是SPI?Dubbo的源码中大量涉及了JavaSPI设计思想,所以理解SPI对理解Dubbo源码有很大帮助。JavaSPI全称JavaServiceProviderInterface,是Java提供的一种服务提供者发现机制。其核心功能是通过接口找到其实现类。在实际运用中,主要用在程序启动或者运行时,通过SPI机......
  • 4.JAVA的特性和优势
    4.JAVA的特性和优势跨平台/可移植性这是Java的核心优势。Java在设计时就很注重移植和跨平台性。比如:Java的int永远都是32位。不像C++可能是16,32,可能是根据编译器厂商规定的变化。这样的话程序的移植就会非常麻烦。安全性Java适合于网络/分布式环境,为了达到这个目标,在安全性......
  • JAVA体系结构
    JAVA体系结构JavaSE(Java Standard Edition):标准版,定位在个人计算机上的应用这个版本是Java平台的核心,它提供了非常丰富的API来开发一般个人计算机上的应用程序,包括用户界面接口AWT及Swing,网络功能与国际化、图像处理能力以及输入输出支持等。在上世纪90年代末互联网上大放异......