首页 > 编程语言 >java之并发编程(上)

java之并发编程(上)

时间:2023-02-22 22:22:14浏览次数:46  
标签:java synchronized Thread lock void 编程 并发 new public

回顾

1、线程与进程

进程:正在运行的程序,进程包含至少一个或多个线程

2、创建线程的方式

  • 实现Runable接口
  • 继承Thread类(不建议使用,java是单继承,可扩展性差),用start方法通知cpu创建一个线程
  • 但在公司中一般都是用Callable接口,Runable接口的效率比Callable的相对较低
  • 使用线程池ThreadPoolExecutor

3、java真的可以开启线程吗

实际上我们调用的start()方法本质上是调用了系统的C++程序,这个程序才是真正操作计算机硬件的,而我们的java程序不是直接运行在操作系统上而是运行在JVM上,所以java程序无法直接操作硬件。

4、并发(队列+锁)与并行

并发:多个线程操作同一资源,单核,模拟出多条线程,天下武功,唯快不破,快速交替

并行(一起行走):多个cup,多个线程同时进行,使用线程池

并发编程的本质:充分利用cpu的资源/时间

5、synchronized与lock锁

  1. synchronized 是java内置关键字,lock是一个java类。
  2. synchronized 会自动释放锁,lock需要手动加锁,会死锁。
  3. synchronized (线程1(获得锁,阻塞),线程2(傻傻的等待)),lock会尝试获取锁
  4. synchronized 适合锁少量代码,lock适合锁大量代码
  5. synchronized 不会判断锁定状态,lock会判断是否有锁
  6. synchronized 可重入锁,非公平,lock ,可重入锁,自己设置非公平或公平

6、wait()与sleep()

  • wait()--->来自object类,sleep()---->来自Thread类
  • wait()---->人醒着,在等待 ,会释放锁 ; sleep()---->人在睡觉,不会释放锁

预科

1、获取cpu核数

public class saleTicket {
    public static void main(String[] args) {
        //开启多个线程去买票
        Ticket ticket=new Ticket();
        //使用lambda表达式,简洁代码
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        }).start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        }).start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        }).start();
    }
}
//实际编程,高内聚,低耦合
//oop编程,代码干净,简洁
class Ticket{
    private int num=20;
    //卖票方法
    public synchronized void sale(){
        if(num>0) {
            System.out.println(Thread.currentThread().getName() + "买了第" + (num--) + "票===" + "剩余" + num);
        }
    }
}

3、lock锁:与synchronized实现同样的效果

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

public class saleTicket2 {
    public static void main(String[] args) {
        Ticket2 ticket=new Ticket2();
        //使用lambda表达式,简洁代码
        new Thread(()->{ for (int i = 0; i < 30; i++) ticket.sale();},"A").start();
        new Thread(()->{ for (int i = 0; i < 30; i++) ticket.sale();},"B").start();
        new Thread(()->{ for (int i = 0; i < 30; i++) ticket.sale();},"C").start();

    }

}
//使用lock锁
/*1、new ReentrantLock()一把锁
* 2、加锁 lock()
* 3、释放锁 unlock()
* */
class Ticket2{
    private int num=20;
    //卖票方法
    public synchronized void sale(){
        Lock lock=new ReentrantLock();
        lock.lock();
        try {//业务
            if(num>0) {
                System.out.println(Thread.currentThread().getName() + "买了第" + (num--) + "票===" + "剩余" + num);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

6、生产者消费者问题之lock的精准通知

新技术的出现不仅仅为了覆盖传统技术,还有对技术的补充和升级

lock锁与synchronized都能实现同样的效果,但是如何做到有序的使用资源即精准的通知,如:A线程昨晚去通知B线程,B->C->D,这样ABCD轮流,只有lock锁能实现

- 传统的synchronized解决

能够解决资源抢夺问题,但不能保证线程顺序

//使用传统的synchronized方法时
//超过两个线程对资源进行操作时,synchronized无法保证线程的安全了
//由此引发一个问题,”虚假唤醒“
/*虚假唤醒的问题在于,只进行了一次判断,但是虚假唤醒总是有可能发生,所以建议使用循环
if(number!=0){//等待
            this.wait();
        }
*
* */
public class oldPC {
    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) {
                e.printStackTrace();
            }
        }
        },"A").start();

        new Thread(()->{ for (int i = 0; i <20 ; i++) {
            try {
                data.decrese();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"B").start();

        new Thread(()->{ for (int i = 0; i <20 ; i++) {
            try {
                data.decrese();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"C").start();

        new Thread(()->{ for (int i = 0; i <20 ; i++) {
            try {
                data.decrese();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"D").start();
    }
}
//oop编程
class Data{
    private int number=0;
    //+1操作
    public synchronized void increment() throws InterruptedException {
        while(number!=0){//等待
            this.wait();
        }
        //执行+1后唤醒其他线程
        number++;
        System.out.println(Thread.currentThread().getName()+"执行了==>"+number);
        this.notifyAll();
    }

    //-1操作
    public synchronized void decrese() throws InterruptedException {
        while(number==0){//等待
            this.wait();
        }
        //执行-1后唤醒其他线程
        number--;
        System.out.println(Thread.currentThread().getName()+"执行了==>"+number);
        this.notifyAll();
    }

}

-使用lock方式:

lock去newCondition,使用方法await(),signal()

public class NewPC {
    public static void main(String[] args) {
        Data2 data2=new Data2();
        new Thread(()->{for (int i = 0; i < 20; i++) data2.increse();},"A").start();
        new Thread(()->{for (int i = 0; i < 20; i++) data2.decrese();},"B").start();
        new Thread(()->{for (int i = 0; i < 20; i++) data2.increse();},"C").start();
       // new Thread(()->{for (int i = 0; i < 20; i++) data2.decrese();},"D").start();
    }
}
/*使用lock方式
* 通过lock去newCondition
* 使用await(),signal()
* */
class Data2{
    private int number=0;
    Lock lock=new ReentrantLock();
    Condition condition1=lock.newCondition();
    Condition condition2=lock.newCondition();
    //+1操作
    public void increse(){
        lock.lock();
        try {
            //判断是否等待
            while (number!=0){
                condition1.await();//等待
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"执行了加===>

标签:java,synchronized,Thread,lock,void,编程,并发,new,public
From: https://www.cnblogs.com/littleworld/p/17146229.html

相关文章

  • java基础之网络编程
    1.1网络编程中的两个主要问题:如何准确定位网络中的一台主机主机之间如何通信1.2网络中的主要元素IP地址,端口号port,套接字socket主要的通信协议tcp,udpIP地......
  • Java集合
    Java集合Java集合类型分为:Collection和Map,Collection子接口有:Set、Queue和List接口,每一种接口描述了一种数据结构。1、ListList集合是有序的,可以重复出现。List接口的......
  • JavaScript迭代协议解读
    JavaScript迭代协议解读迭代协议分为可迭代协议和迭代器协议。协议指约定俗成的一系列规则。可迭代协议可迭代协议规定了怎么样算是一个可迭代对象:可迭代对象或其原......
  • 【JS】JavaScript进阶 ES6 - 黑马视频笔记
    1.作用域作用域(scope)规定了变量能够被访问的“范围”,离开这个范围变量便不能被访问。分为:局部作用域、全局作用域。1.1局部作用域局部作用域分为:函数作用域、块作用......
  • 【Java对象转换】003- Java 对象与 Yaml 互转
    【Java对象转换】003-Java对象与Yaml互转文章目录​​【Java对象转换】003-Java对象与Yaml互转​​​​一、Java对象与Yaml概述​​​​1、Java对象​​​​2、......
  • Java 扫描枚举类并获取属性
    Java扫描枚举类并获取属性文章目录​​Java扫描枚举类并获取属性​​​​第一步:在pom.xml下导入hutool和commons-lang3​​​​第二步:写一个接口以规范枚举的属性​......
  • 【Java对象转换】002- Java 对象与 Map 互转
    文章目录​​【Java对象转换】002-Java对象与Map互转​​​​一、Java对象与Map概述​​​​1、Java对象​​​​2、Map​​​​二、Java对象与Map互转​​​​1......
  • Java 截取字符串 split 方法与 substring 方法简单比较
    Java截取字符串split方法与substring方法简单比较文章目录​​Java截取字符串`split`方法与`substring`方法简单比较​​​​0、结论​​​​1、截取目标​​​​......
  • 【Java对象转换】001- Java 对象与 JSON 互转
    文章目录​​【Java对象转换】001-Java对象与JSON互转​​​​一、Java对象与JSON概述​​​​1、Java对象​​​​2、JSON​​​​二、JSON解析及与Java对象互转......
  • 【TypeScript 编程】001-002 第 1 章 导言 与 第 2 章 TypeScript 概述
    【TypeScript编程】001-002第1章导言与第2章TypeScript概述文章目录​​【TypeScript编程】001-002第1章导言与第2章TypeScript概述​​​​第1章......