java并发问题概述

article/2025/8/7 1:58:14
转自 https://www.jb51.net/article/131411.htm

java并发问题概述

转载  更新时间:2017年12月25日 09:28:54   作者:人圭先生   我要评论

这篇文章主要介绍了java并发问题概述,具有一定借鉴价值,需要的朋友可以参考下。

1什么是并发问题。

多个进程或线程同时(或着说在同一段时间内)访问同一资源会产生并发问题。

银行两操作员同时操作同一账户就是典型的例子。比如A、B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户减去50元,A先提交,B后提交。最后实际账户余额为1000-50=950元,但本该为1000+100-50=1050。这就是典型的并发问题。如何解决?可以用锁。

2java中synchronized的用法

用法1

public class Test{public synchronized void print(){….;}
}

某线程执行print()方法,则该对象将加锁。其它线程将无法执行该对象的所有synchronized块。

用法2

public class Test{public void print(){synchronized(this){//锁住本对象 …;}}
}

同用法1, 但更能体现synchronized用法的本质。

用法3

public class Test{private String a = “test”;public void print(){synchronized(a){//锁住a对象 …;}}public synchronized void t(){…;//这个同步代码块不会因为print()而锁定.}
}

执行print(),会给对象a加锁,注意不是给Test的对象加锁,也就是说Test对象的其它synchronized方法不会因为print()而被锁。同步代码块执行完,则释放对a的锁。

为了锁住一个对象的代码块而不影响该对象其它synchronized块的高性能写法:

public class Test{private byte[] lock = new byte[0];public void print(){synchronized(lock){…;}}public synchronized void t(){…;}
}

静态方法的锁

public class Test{public synchronized static void execute(){…;}
}

效果同

public class Test{public static void execute(){synchronized(TestThread.class){…;}}
}

3 Java中的锁与排队上厕所。

锁就是阻止其它进程或线程进行资源访问的一种方式,即锁住的资源不能被其它请求访问。在JAVA中,sychronized关键字用来对一个对象加锁。比如:

public class MyStack {int idx = 0;char [] data = new char[6];public synchronized void push(char c) {data[idx] = c;idx++;}public synchronized char pop() {idx--;return data[idx];}public static void main(String args[]){MyStack m = new MyStack();/**下面对象m被加锁。严格的说是对象m的所有synchronized块被加锁。如果存在另一个试图访问m的线程T,那么T无法执行m对象的push和pop方法。*/m.pop();//对象m被加锁。}
}

Java的加锁解锁跟多个人排队等一个公共厕位完全一样。第一个人进去后顺手把门从里面锁住,其它人只好排队等。第一个人结束后出来时,门才会打开(解锁)。轮到第二个人进去,同样他又会把门从里面锁住,其它人继续排队等待。

用厕所理论可以很容易明白:一个人进了一个厕位,这个厕位就会锁住,但不会导致另一个厕位也被锁住,因为一个人不能同时蹲在两个厕位里。对于Java就是说:Java中的锁是针对同一个对象的,不是针对class的。看下例:

MyStatckm1=newMyStack();
MyStatckm2=newMystatck();
m1.pop();
m2.pop();

m1对象的锁是不会影响m2的锁的,因为它们不是同一个厕位。就是说,假设有3线程t1,t2,t3操作m1,那么这3个线程只可能在m1上排队等,假设另2个线程t8,t9在操作m2,那么t8,t9只会在m2上等待。而t2和t8则没有关系,即使m2上的锁释放了,t1,t2,t3可能仍要在m1上排队。原因无它,不是同一个厕位耳。

Java不能同时对一个代码块加两个锁,这和数据库锁机制不同,数据库可以对一条记录同时加好几种不同的锁。

4何时释放锁?

一般是执行完毕同步代码块(锁住的代码块)后就释放锁,也可以用wait()方式半路上释放锁。wait()方式就好比蹲厕所到一半,突然发现下水道堵住了,不得已必须出来站在一边,好让修下水道师傅(准备执行notify的一个线程)进去疏通马桶,疏通完毕,师傅大喊一声:“已经修好了”(notify),刚才出来的同志听到后就重新排队。注意啊,必须等师傅出来啊,师傅不出来,谁也进不去。也就是说notify后,不是其它线程马上可以进入封锁区域活动了,而是必须还要等notify代码所在的封锁区域执行完毕从而释放锁以后,其它线程才可进入。

这里是wait与notify代码示例:

public synchronized char pop() {char c;while (buffer.size() == 0) {try {this.wait();//从厕位里出来}catch (InterruptedException e) {// ignore it…}}c = ((Character)buffer.remove(buffer.size()-1)). charValue();return c;
}
public synchronized void push(char c) {this.notify();//通知那些wait()的线程重新排队。注意:仅仅是通知它们重新排队。 Character charObj = new Character(c);buffer.addElement(charObj);
}
//执行完毕,释放锁。那些排队的线程就可以进来了。

再深入一些。

由于wait()操作而半路出来的同志没收到notify信号前是不会再排队的,他会在旁边看着这些排队的人(其中修水管师傅也在其中)。注意,修水管的师傅不能插队,也得跟那些上厕所的人一样排队,不是说一个人蹲了一半出来后,修水管师傅就可以突然冒出来然后立刻进去抢修了,他要和原来排队的那帮人公平竞争,因为他也是个普通线程。如果修水管师傅排在后面,则前面的人进去后,发现堵了,就wait,然后出来站到一边,再进去一个,再wait,出来,站到一边,只到师傅进去执行notify.这样,一会儿功夫,排队的旁边就站了一堆人,等着notify.

终于,师傅进去,然后notify了,接下来呢?

1.有一个wait的人(线程)被通知到。

2.为什么被通知到的是他而不是另外一个wait的人?取决于JVM.我们无法预先

判断出哪一个会被通知到。也就是说,优先级高的不一定被优先唤醒,等待

时间长的也不一定被优先唤醒,一切不可预知!(当然,如果你了解该JVM的

实现,则可以预知)。

3.他(被通知到的线程)要重新排队。

4.他会排在队伍的第一个位置吗?回答是:不一定。他会排最后吗?也不一定。

但如果该线程优先级设的比较高,那么他排在前面的概率就比较大。

5.轮到他重新进入厕位时,他会从上次wait()的地方接着执行,不会重新执行。

恶心点说就是,他会接着拉巴巴,不会重新拉。

6.如果师傅notifyAll().则那一堆半途而废出来的人全部重新排队。顺序不可知。

JavaDOC上说,Theawakenedthreadswillnotbeabletoproceeduntilthecurrentthreadrelinquishesthelockonthisobject(当前线程释放锁前,唤醒的线程不能去执行)。

这用厕位理论解释就是显而易见的事。

5Lock的使用

用synchronized关键字可以对资源加锁。用Lock关键字也可以。它是JDK1.5中新增内容。用法如下:

class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();final Condition notEmpty = lock.newCondition();final Object[] items = new Object[100];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {lock.lock();try {while (count == items.length) notFull.await();items[putptr] = x;if (++putptr == items.length) putptr = 0;++count;notEmpty.signal();}finally {lock.unlock();}}public Object take() throws InterruptedException {lock.lock();try {while (count == 0) notEmpty.await();Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;notFull.signal();return x;}finally {lock.unlock();}}
}

(注:这是JavaDoc里的例子,是一个阻塞队列的实现例子。所谓阻塞队列,就是一个队列如果满了或者空了,都会导致线程阻塞等待。Java里的ArrayBlockingQueue提供了现成的阻塞队列,不需要自己专门再写一个了。)

一个对象的lock.lock()和lock.unlock()之间的代码将会被锁住。这种方式比起synchronize好在什么地方?简而言之,就是对wait的线程进行了分类。用厕位理论来描述,则是那些蹲了一半而从厕位里出来等待的人原因可能不一样,有的是因为马桶堵了,有的是因为马桶没水了。通知(notify)的时候,就可以喊:因为马桶堵了而等待的过来重新排队(比如马桶堵塞问题被解决了),或者喊,因为马桶没水而等待的过来重新排队(比如马桶没水问题被解决了)。这样可以控制得更精细一些。不像synchronize里的wait和notify,不管是马桶堵塞还是马桶没水都只能喊:刚才等待的过来排队!假如排队的人进来一看,发现原来只是马桶堵塞问题解决了,而自己渴望解决的问题(马桶没水)还没解决,只好再回去等待(wait),白进来转一圈,浪费时间与资源。

Lock方式与synchronized对应关系:

LockawaitsignalsignalAll

synchronizedwaitnotifynotifyAll

注意:不要在Lock方式锁住的块里调用wait、notify、notifyAll

6利用管道进行线程间通信

原理简单。两个线程,一个操作PipedInputStream,一个操作PipedOutputStream。PipedOutputStream写入的数据先缓存在Buffer中,如果Buffer满,此线程wait。PipedInputStream读出Buffer中的数据,如果Buffer没数据,此线程wait。

jdk1.5中的阻塞队列可实现同样功能。

package io;
import java.io.*;
public class PipedStreamTest {public static void main(String[] args) {PipedOutputStream ops=new PipedOutputStream();PipedInputStream pis=new PipedInputStream();try{ops.connect(pis);//实现管道连接 new Producer(ops).run();new Consumer(pis).run();}catch(Exception e){e.printStackTrace();}}
}
//生产者 
class Producer implements Runnable{private PipedOutputStream ops;public Producer(PipedOutputStream ops) {this.ops=ops;}public void run(){try{ops.write("hell,spell".getBytes());ops.close();}catch(Exception e){e.printStackTrace();}}
}
//消费者 
class Consumer implements Runnable{private PipedInputStream pis;public Consumer(PipedInputStream pis) {this.pis=pis;}public void run(){try{byte[] bu=new byte[100];int len=pis.read(bu);System.out.println(new String(bu,0,len));pis.close();}catch(Exception e){e.printStackTrace();}}
}

例2 对上面的程序做少许改动就成了两个线程。

package io;
import java.io.*;
public class PipedStreamTest {public static void main(String[] args) {PipedOutputStream ops=new PipedOutputStream();PipedInputStream pis=new PipedInputStream();try{ops.connect(pis);//实现管道连接 Producer p = new Producer(ops);new Thread(p).start();Consumer c = new Consumer(pis);new Thread(c).start();}catch(Exception e){e.printStackTrace();}}
}
//生产者 
class Producer implements Runnable{private PipedOutputStream ops;public Producer(PipedOutputStream ops) {this.ops=ops;}public void run(){try{for (;;){ops.write("hell,spell".getBytes());ops.close();}}catch(Exception e){e.printStackTrace();}}
}
//消费者 
class Consumer implements Runnable{private PipedInputStream pis;public Consumer(PipedInputStream pis) {this.pis=pis;}public void run(){try{for (;;){byte[] bu=new byte[100];int len=pis.read(bu);System.out.println(new String(bu,0,len));}pis.close();}catch(Exception e){e.printStackTrace();}}
}

例3. 这个例子更加贴进应用

import java.io.*;
public class PipedIO {//程序运行后将sendFile文件的内容拷贝到receiverFile文件中 public static void main(String args[]){try{//构造读写的管道流对象 PipedInputStream pis=new PipedInputStream();PipedOutputStream pos=new PipedOutputStream();//实现关联 pos.connect(pis);//构造两个线程,并且启动。 new Sender(pos,”c:\text2.txt”).start();new Receiver(pis,”c:\text3.txt”).start();}catch(IOException e){System.out.println(“Pipe Error”+ e);}}
}
//线程发送 
class Sender extends Thread{PipedOutputStream pos;File file;//构造方法 Sender(PipedOutputStream pos, String fileName){this.pos=pos;file=new File(fileName);}//线程运行方法 public void run(){try{//读文件内容 FileInputStream fs=new FileInputStream(file);int data;while((data=fs.read())!=-1){//写入管道始端 pos.write(data);}pos.close();}catch(IOException e) {System.out.println(“Sender Error” +e);}}
}
//线程读 
class Receiver extends Thread{PipedInputStream pis;File file;//构造方法 Receiver(PipedInputStream pis, String fileName){this.pis=pis;file=new File(fileName);}//线程运行 public void run(){try {//写文件流对象 FileOutputStream fs=new FileOutputStream(file);int data;//从管道末端读 while((data=pis.read())!=-1){//写入本地文件    fs.write(data);}pis.close();}catch(IOException e){System.out.println("Receiver Error" +e);}}
}

7阻塞队列

阻塞队列可以代替管道流方式来实现进水管/排水管模式(生产者/消费者).JDK1.5提供了几个现成的阻塞队列.现在来看ArrayBlockingQueue的代码如下:

这里是一个阻塞队列

BlockingQueue blockingQ = new ArrayBlockingQueue 10; 

一个线程从队列里取

for(;;){ 
Object o = blockingQ.take();//队列为空,则等待(阻塞) 
} 

另一个线程往队列存

for(;;){ 
blockingQ.put(new Object());//队列满,则等待(阻塞) 
} 

可见,阻塞队列使用起来比管道简单。

8使用Executors、Executor、ExecutorService、ThreadPoolExecutor

可以使用线程管理任务。还可以使用jdk1.5提供的一组类来更方便的管理任务。从这些类里我们可以体会一种面向任务的思维方式。这些类是:

Executor接口。使用方法:

Executor executor = anExecutor;//生成一个Executor实例。 
executor.execute(new RunnableTask1()); 

用意:使用者只关注任务执行,不用操心去关注任务的创建、以及执行细节等这些第三方实现者关心的问题。也就是说,把任务的调用执行和任务的实现解耦。

实际上,JDK1.5中已经有该接口出色的实现。够用了。

Executors是一个如同Collections一样的工厂类或工具类,用来产生各种不同接口的实例。

ExecutorService接口它继承自Executor.Executor只管把任务扔进executor()里去执行,剩余的事就不管了。而ExecutorService则不同,它会多做点控制工作。比如:

class NetworkService {private final ServerSocket serverSocket;private final ExecutorService pool;public NetworkService(int port, int poolSize) throws IOException {serverSocket = new ServerSocket(port);pool = Executors.newFixedThreadPool(poolSize);}public void serve() {try {for (;;) {pool.execute(new Handler(serverSocket.accept()));}}catch (IOException ex) {pool.shutdown();//不再执行新任务}}
}
class Handler implements Runnable {private final Socket socket;Handler(Socket socket) {this.socket = socket;}public void run() {// read and service request}
}

ExecutorService(也就是代码里的pool对象)执行shutdown后,它就不能再执行新任务了,但老任务会继续执行完毕,那些等待执行的任务也不再等待了。

任务提交者与执行者通讯

public static void main(String args[])throws Exception {ExecutorService executor = Executors.newSingleThreadExecutor();Callable task = new Callable(){public String call()throws Exception{return “test”;}};Future f = executor.submit(task);String result = f.get();//等待(阻塞)返回结果 System.out.println(result);executor.shutdown();
}

Executors.newSingleThreadExecutor()取得的Executor实例有以下特性:

任务顺序执行.比如:

executor.submit(task1); 
executor.submit(task2); 

必须等task1执行完,task2才能执行。

task1和task2会被放入一个队列里,由一个工作线程来处理。即:一共有2个线程(主线程、处理任务的工作线程)。

其它的类请参考JavaDoc

9并发流程控制

本节例子来自温少的Java并发教程,可能会有改动。向温少致敬。

CountDownLatch门插销计数器

启动线程,然后等待线程结束。即常用的主线程等所有子线程结束后再执行的问题。

public static void main(String[] args)throws Exception {// TODO Auto-generated method stub final int count=10;final CountDownLatch completeLatch = new CountDownLatch(count);//定义了门插销的数目是10for (int i=0;i<count;i++){Thread thread = new Thread("worker thread"+i){public void run(){//do xxxx                  completeLatch.countDown();//减少一根门插销}};thread.start();}completeLatch.await();//如果门插销还没减完则等待。
}

JDK1.4时,常用办法是给子线程设置状态,主线程循环检测。易用性和效率都不好。

启动很多线程,等待通知才能开始

public static void main(String[] args) throws Exception {// TODO Auto-generated method stub final CountDownLatch startLatch = new CountDownLatch(1);//定义了一根门插销for (int i = 0; i < 10; i++) {Thread thread = new Thread("worker thread" + i) {public void run() {try {startLatch.await();//如果门插销还没减完则等待}catch (InterruptedException e) {}// do xxxx}};thread.start();}startLatch.countDown();//减少一根门插销
}

CycliBarrier. 等所有线程都达到一个起跑线后才能开始继续运行。

public class CycliBarrierTest implements Runnable {private CyclicBarrier barrier;public CycliBarrierTest(CyclicBarrier barrier) {this.barrier = barrier;}public void run() {//do xxxx;try {this.barrier.await();//线程运行至此会检查是否其它线程都到齐了,没到齐就继续等待。到齐了就执行barrier的run函数体里的内容}catch (Exception e) {}}/*** @param args*/public static void main(String[] args) {//参数2代表两个线程都达到起跑线才开始一起继续往下执行CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() {public void run() {//do xxxx;}});Thread t1 = new Thread(new CycliBarrierTest(barrier));Thread t2 = new Thread(new CycliBarrierTest(barrier));t1.start();t2.start();}
}

这简化了传统的用计数器+wait/notifyAll来实现该功能的方式。

10并发3定律

Amdahl定律.给定问题规模,可并行化部分占12%,那么即使把并行运用到极致,系统的性能最多也只能提高1/(1-0.12)=1.136倍。即:并行对提高系统性能有上限。

Gustafson定律.Gustafson定律说Amdahl定律没有考虑随着cpu的增多而有更多的计算能力可被使用。其本质在于更改问题规模从而可以把Amdahl定律中那剩下的88%的串行处理并行化,从而可以突破性能门槛。本质上是一种空间换时间。

Sun-Ni定律.是前两个定律的进一步推广。其主要思想是计算的速度受限于存储而不是CPU的速度.所以要充分利用存储空间等计算资源,尽量增大问题规模以产生更好/更精确的解.

11由并发到并行

计算机识别物体需要飞速的计算,以至于芯片发热发烫,而人在识别物体时却一目了然,却并不会导致某个脑细胞被烧热烧焦(夸张)而感到不适,是由于大脑是一个分布式并行运行系统,就像google用一些廉价的linux服务器可以进行庞大复杂的计算一样,大脑内部无数的神经元的独自计算,互相分享成果,从而瞬间完成需要单个cpu万亿次运算才能有的效果。试想,如果在并行处理领域有所创建,将对计算机的发展和未来产生不可估量的影响。当然,其中的挑战也可想而知:许多的问题是并不容易轻易就“分割”的了的。

总结

以上就是本文关于java并发问题概述的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

您可能感兴趣的文章:

  • Java并发问题之乐观锁与悲观锁
  • java并发编程之同步器代码示例
  • 深入分析java并发编程中volatile的实现原理
  • 聊聊Java并发中的Synchronized
  • Java并发实例之CyclicBarrier的使用
  • java并发等待条件的实现原理详解
  • java并发学习之BlockingQueue实现生产者消费者详解
  • Java并发底层实现原理学习心得

  • java
  • 并发问题

相关文章

  • 利用POI读取word、Excel文件的最佳实践教程

    利用POI读取word、Excel文件的最佳实践教程

    Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。 下面这篇文章主要给大家介绍了关于利用POI读取word、Excel文件的最佳实践的相关资料,需要的朋友可以参考下。
    2017-11-11
  • java微信公众号开发(搭建本地测试环境)

    java微信公众号开发(搭建本地测试环境)

    这篇文章主要介绍了java微信公众号开发,主要内容有测试公众号与本地测试环境搭建,需要的朋友可以参考下
    2015-12-12
  • Kotlin基础教程之数据类型

    Kotlin基础教程之数据类型

    这篇文章主要介绍了Kotlin基础教程之数据类型的相关资料,需要的朋友可以参考下
    2017-05-05
  • java.net.SocketException: Connection reset 解决方法

    java.net.SocketException: Connection reset 解决方法

    最近纠结致死的一个java报错java.net.SocketException: Connection reset 终于得到解决
    2013-03-03
  • java 使用ConcurrentHashMap和计数器实现锁

    java 使用ConcurrentHashMap和计数器实现锁

    这篇文章主要介绍了java 使用ConcurrentHashMap和计数器实现锁的相关资料,需要的朋友可以参考下
    2017-05-05
  • hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法

    hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法

    这篇文章主要介绍了hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法,需要的朋友可以参考下
    2017-09-09
  • Java精确抽取网页发布时间

    Java精确抽取网页发布时间

    这篇文章主要为大家详细介绍了Java精确抽取网页发布时间的相关资料,尽量做到精确无误,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Java成员变量与局部变量(动力节点Java学院整理)

    Java成员变量与局部变量(动力节点Java学院整理)

    这篇文章主要介绍了Java成员变量与局部变量的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-04-04
  • Spring boot + thymeleaf 后端直接给onclick函数赋值的实现代码

    Spring boot + thymeleaf 后端直接给onclick函数赋值的实现代码

    这篇文章主要介绍了Spring boot + thymeleaf 后端直接给onclick函数赋值的实现代码,需要的朋友可以参考下
    2017-06-06
  • JAVA算法起步之插入排序实例

    JAVA算法起步之插入排序实例

    这篇文章主要介绍了JAVA算法起步之插入排序实例,需要的朋友可以参考下
    2014-02-02

大家感兴趣的内容

  • 1java使double保留两位小数的多方
  • 2JAVA8 十大新特性详解
  • 3java.net.SocketException: Conn
  • 4java写入文件的几种方法分享
  • 5Java环境变量的设置方法(图文教程
  • 6JAVA 十六进制与字符串的转换
  • 7java list用法示例详解
  • 8java中File类的使用方法
  • 9JavaWeb实现文件上传下载功能实例
  • 10Java中HashMap和TreeMap的区别深

最近更新的内容

  • 详解Spring Boot 集成Shiro和CAS
  • Java自定义简单标签实例
  • Hibernate中Session增删改查操作代码详解
  • Java处理InterruptedException异常的理论
  • java编程调用存储过程中得到新增记录id号
  • IDEA Maven Mybatis generator 自动生成代
  • java读取excel文件的两种方法
  • Eclipse配置springIDE插件的方法步骤
  • Java将GeoHash转化为对应的经纬度坐标实例
  • 基于Java class对象说明、Java 静态变量声



http://chatgpt.dhexx.cn/article/dB3aOh76.shtml

相关文章

【Java基础系列教程】第一章 编程入门

一、计算机概述 1.1 计算机简介 计算机&#xff08;computer&#xff09;俗称电脑&#xff0c;是现代一种用于高速计算的电子计算机器&#xff0c;可以进行数值计算&#xff0c;又可以进行逻辑计算&#xff0c;还具有存储记忆功能。是能够按照程序运行&#xff0c;自动、高速处…

关于程序员这14条经典定律,我全中~

定律1:最难定位的问题要么是最疑难的问题,要么是最低级的问题,这两种问题都有一个共同特征,就是让你意想不到。 举一个例子,一次代码编译不过,报函数没有定义,开始怀疑是类没有“;”结束符,然后怀疑有没有匹配的“{”,折腾了好久,最后才发现是开头的“#ifndef”定义…

系统性能优化的十大策略(强烈推荐,建议收藏)

点击关注公众号&#xff0c;实用技术文章及时了解 上篇 提升系统性能&#xff0c;榨干计算机资源是程序员的极致追求&#xff0c;今天跟大家聊聊性能优化。分为上中下三篇&#xff0c;由浅及深的写了关于性能优化的方方面面&#xff0c;并不仅仅局限于代码层面&#xff0c;希望…

JAVA工程师的十大借口,你知道哪些?

他们是近几十年来出现的新物种。他们的着装可能经常会遭到别人的吐槽&#xff0c;他们的玩笑可能别人也经常get不到笑点&#xff0c;他们心照不宣的执着让外人觉得莫名其妙。但同时&#xff0c;他们也拥有无与伦比的耐力&#xff0c;超越时代的智商&#xff0c;和横穿社会的自虐…

二八定律全面分析

二八定律 也叫 巴莱多定律 &#xff0c;是19世纪末20世纪初 意大利 经济学家巴莱多发明的。他认为&#xff0c;在任何一组东西中&#xff0c;最重要的只占其中一小部分&#xff0c;约20%&#xff0c;其余80%的尽管是多数&#xff0c;却是次要的&#xff0c;因此又称二八法则。 …

【网络技术】什么是CNI

序言 你只管努力&#xff0c;其他交给时间&#xff0c;时间会证明一切。 Never look back unless you are planning to go that way. 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级论点蓝色&#xff1a;用…

java程序员找工作前需要准备的杀手锏有哪些?

高考前,我们要练兵考试和集训。”临阵磨枪不快也光 ”,找工作前,我们也必须要花很多精力去完成一些必要的准备。 “不打无准备之仗”, 精心准备和训练会对你有相当正面的作用。 有人认为“找工作要靠能力”。这话没错,我要说的是,“临阵磨枪准备的内容也是能力的一部分”…

《Java性能优化全攻略》分享

作为Java程序员&#xff0c;你希望写出高性能的代码吗&#xff1f; 什么样的互联网服务质量好?代码的高性能是必备的一环。怎样才能降低公司运营成本?提高系统容量的效率&#xff08;服务器和数据中心&#xff09;是重要的一部分。 代码看性能&#xff0c;公司重效率。怎么…

java技术点

后端架构师技术图谱 推荐: 《Java技术书籍大全》 - awesome-java-books 从初级开发者到资深架构师&#xff0c;看这些书就够了 数据结构 队列集合链表、数组字典、关联数组栈树 二叉树完全二叉树平衡二叉树二叉查找树&#xff08;BST&#xff09;红黑树B&#xff0c;B&#x…

有用但多疑的十大Java编程技术

在编码过一段时间后(哎呀&#xff0c;拿我来说&#xff0c;已经20多年了&#xff0c;当你乐享其中时&#xff0c;时间过得飞快&#xff09;&#xff0c;有人已经开始拥抱他们的习惯了。 因为&#xff0c;你知道… “会出错的事情总会出错”– 墨菲定律 这就是人们拥抱“自卫…

40000+字超强总结?阿里P8把Java全栈知识体系详解整理成这份PDF

40000 字长文总结&#xff0c;已将此文整理成PDF文档了&#xff0c;需要的朋友点赞支持一下吧。 全栈知识体系总览 Java入门与进阶面向对象与Java基础 Java 基础 - 面向对象Java 基础 - 知识点Java 基础 - 图谱 & Q/A 基础知识点复习完了以后&#xff0c;我们需要深入的理…

2020面试准备之Java 基础(理论篇)

文章目录 1、面向对象和面向过程的区别2、Java 语言有哪些特点?3、什么是 Java 虚拟机&#xff1f;为什么 Java 被称作是“平台无关的编程语言”&#xff1f;4、JDK 和 JRE 的区别是什么&#xff1f;5、Java 和 C的区别?6、面向对象的特征有哪些方面&#xff1f;7、访问修饰符…

资深程序员总结的成功十大黄金定律

《天下无贼》中由葛优饰演的黎叔曾说过一句话&#xff1a;“21世界什么最贵&#xff1f;——人才最贵。”人才对成功来说至关重要&#xff0c;而且人才和天才还是不一样的&#xff0c;天才大部分是要有天赋的&#xff0c;而人才即使你没有天赋&#xff0c;遵照规律发展&#xf…

什么是汉明窗?加Hanmming窗的作用?

1.什么是汉明窗&#xff1f; 从语音的角度说 理论&#xff1a; 语音信号是一种非平稳的时变信号&#xff0c;其产生过程与发声器官的运动紧密相关。而发声器官的状态变化速度较声音振动的速度要缓慢的多&#xff0c;因此语音信号可以认为是短时平稳的。研究发现&#xff0c;在…

hanmming窗和hamming窗的作用

什么是汉明窗&#xff1f;加Hanmming窗的作用&#xff1f; 1.什么是汉明窗&#xff1f; 答&#xff1a;我是做语音识别的&#xff0c;我就从语音的角度跟你说一下吧。 语音信号一般在10ms到30ms之间&#xff0c;我们可以把它看成是平稳的。为了处理语音信号&#xff0c;我们要对…

LFM回波信号仿真,加汉明窗,可用的matlab代码

LFM回波信号仿真&#xff0c;加汉明窗&#xff0c;可用的matlab代码 运行结果&#xff08;文尾有程序&#xff09; 在数字信号处理过程中&#xff0c;每次FFT变换只能对有限长度的时域数据进行变换&#xff0c;因此&#xff0c;需要对时域信号进行信号截断。 即使是周期信号&…

matlab汉明窗dft,谱分析中窗的选取

信号截断及能量泄漏效应 数字信号处理的主要数学工具是傅里叶变换,而傅里叶变换是研究整个时间域和频率域的关系。然而,当运用计算机实现工程测试信号处理时,不可能对无限长的信号进行测量和运算,而是取其有限的时间片段进行分析。取用有限个数据,就是将信号进行加窗函数操…

语音信号处理(二):矩形窗和汉明窗时域波形和频域波形

一&#xff1a;通过代码实现 clear all; hzeros(10000,1); h(2001:8000)1; % 在2001-8000上令值为1 subplot(2,2,1); plot(h,r-); title(矩形窗时域波形); xlabel(样点数); ylabel(幅度); hold on; axis([0 10000 0 1.5]);wh(2001:2060); Wfft(w,1024); % 对w进行1024点fft计…

语音识别之——mfcc什么是汉明窗,为什么加汉明窗

为什么要加汉明窗&#xff1f;什么叫加窗&#xff1f; 在信号处理中&#xff0c;可以说加窗处理是一个必经的过程&#xff0c;因为我们的计算机只能处理有限长度的信号&#xff0c;因此原始信号X(t)要以T&#xff08;采样时间&#xff09;截断&#xff0c;即有限化&#xff0c;…

窗方法原理之矩形窗及汉明窗

窗口设计法 窗口设计法是从单位脉冲响应着手&#xff0c;使h(n)逼近理想的单位脉冲响应序列hd(n)。我们知道hd(n)可以通过对理想频响求DTFT反变换获得 理想频响是分段恒定的&#xff0c;在边界频率处有突变点&#xff0c;所以&#xff0c;这样得到的理想滤波器单位脉冲响应hd(n…