当前位置: 首页 > 后端技术 > Java

Java并发编程之多线程

时间:2023-04-01 18:55:20 Java

什么是多线程?因为我的图片,具体可以看我博客上的文章:多线程并发首先我们要先了解什么是进程,什么是线程。首先,让我们看看这个过程。如果我们允许一个程序并且它卡住了,我们通常会去任务管理器结束进程。所以,我们在这里看到的是过程。那么,什么是线程?首先看一下知乎上的解释:线程是进程中进行计算的最小单位,是进程中的实体,是系统独立调度调度的基本单位。线程本身不拥有系统资源,只是运行中的一小部分,是进程中必不可少的资源,但它可以与属于同一进程的其他线程共享本进程拥有的所有资源。一个线程可以创建和取消另一个线程,同一个进程中的多个线程可以并发执行。你是什??么意思?通俗地说。QQ和Chrome浏览器是两个进程。Chrome进程中有很多线程,比如HTTP请求线程、事件响应线程、渲染线程等,线程的并发执行使得在浏览器中点击一个新的链接发起一个HTTP请求成为可能。浏览器还可以响应用户的其他事件,你同时打开多个窗口浏览网页也没问题。想知道更详细的可以看知乎这篇文章-->进程与线程然后腾讯云还有一篇文章,链接是中文的,不好分享,我直接截图了。多线程的优点多线程是多任务处理的一种特殊形式,但多线程使用的资源开销较小。这里定义了另一个与线程相关的术语——进程:进程包括操作系统分配的内存空间,包含一个或多个线程。线程不能独立存在,它必须是进程的一部分。一个进程一直运行到所有非守护线程都运行完为止。多线程可以满足程序员编写高效的程序来充分利用CPU。优点很多,所以直接去网上转一下,只要能达到学习的目的就行,自己描述也无所谓。一、多线程的优点采用多线程技术的应用程序可以更好地利用系统资源。主要优点是充分利用了CPU的空闲时间片,以尽可能少的时间响应用户请求,大大提高了进程的整体运行效率,增强了应用程序的灵活性。由于同一个进程的所有线程共享同一块内存,不需要专门的数据传输机制,不需要建立共享存储区或共享文件,使得不同任务、数据交互、资源的协调和运行分配等问题更容易解决。线程同步,在多线程应用中,考虑不同线程之间的数据同步,防止死锁。当两个或多个线程同时等待对方释放资源时,就会在线程之间形成死锁。为了防止死锁,需要通过同步来实现线程安全。VisualBasic中提供了三种方法来完成线程同步。synchronized关键字在Java中可用。2.代码域同步使用Monitor类可以同步静态/实例化方法的全部或部分代码。3.手动同步你可以使用不同的同步类来创建你自己的同步机制。这种同步方式需要你自己手动同步不同的字段和方法。这种同步方式也可以用于进程间同步,释放等待共享资源造成的死锁。四、上下文同步使用SynchronizationAttribute为ContextBoundObject对象创建简单的自动同步。该同步方法仅用于实例化方法和字段的同步。同一上下文中的所有对象共享同一个锁。总结一下多线程的好处,使用线程可以把程序中耗时较长的任务放到后台处理;用户界面更吸引人,例如,当用户点击一个按钮触发事件的处理时,可以弹出一个进度条来显示处理的进度;可以提高程序的运行效率;在用户输入、文件读取、网络收发数据等一些等待任务的实现中,线程的用处更大。如果上面的很多部分你都不理解,可能是很多东西没有涉及到。实现多线程我们实现Java的多线程,有4个方法。1.继承Thread类创建线程2.实现Runnable接口创建线程3.实现Callable接口通过FutureTask包装器创建Thread线程4.使用ExecutorService、Callable、Future实现有返回结果的线程(线程池方法)多线程是如何工作的?菜鸟教程不行,不过看图还是很好用的。让我们来看看这张照片。如果正常运行,路径是这样的:新建线程-->就绪态-->运行态-->死态Thread类创建线程要使用Thread类创建线程,首先要继承它并覆盖运行方法。只要满足这两个条件。这里为了体现多线程的并发性,我使用Time下的LocalTime类来体现时间的变化。sleep()方法可以设置一个延时,也就是说,运行一次后,我需要1000毫秒才能运行下一次,我会加一个循环来运行它。尝试{for(inti=0;i<3;i++){Thread.sleep(1000);System.out.println(this.getName()+"多线程输出"+LocalTime.now());}}catch(InterruptedExceptione){e.printStackTrace();}创建一个入口类并运行它。包线程;公共类ThreadTest{publicstaticvoidmain(String[]args){ThreadDemot=newThreadDemo();t.开始();ThreadDemot1=newThreadDemo();t1.开始();ThreadDemot2=newThreadDemo();t2.start();}}这里创建了三个线程,可以使用start()方法运行,调用run方法。注意!!!不是.run(),而是.start()。运行后,结果如图所示。Thread-2多线程输出18:29:22.345Thread-1多线程输出18:29:22.345Thread-0多线程输出18:29:22.345//sleep(1000),继续运行Thread-1多-threaded延迟1s后输出18:29:23.356Thread-2多线程输出18:29:23.356Thread-0多线程输出18:29:23.356//sleep(1000),延迟后继续运行of1sThread-1多线程输出18:29:24.357Thread-2多线程输出18:29:24.357Thread-0多线程输出18:29:24.357看后面的时间,T,T1,T2都是都是同时跑的,比如第一次,这次都是18:29:22.345。至于为什么三个对象的顺序不一样,这相当于挤公交了。谁知道谁先挤进去?嘿嘿。Thread方法下表列出了Thread类的一些重要方法:序号方法说明1publicvoidstart()开始线程的执行;Java虚拟机调用线程的run方法。2publicvoidrun()如果这个线程是使用一个独立的Runnablerun对象构造的,调用Runnable对象的run方法;否则,该方法不执行任何操作并返回。3publicfinalvoidsetName(Stringname)把线程名改成和参数名一样。4publicfinalvoidsetPriority(intpriority)改变线程的优先级。5publicfinalvoidsetDaemon(booleanon)将这个线程标记为守护线程或用户线程。6publicfinalvoidjoin(longmillisec)等待此线程终止最多millis毫秒。7publicvoidinterrupt()中断线程。8publicfinalbooleanisAlive()测试线程是否存活。以上方法都是Thread对象调用的,下表中的方法是Thread类的静态方法。序号方法说明1publicstaticvoidyield()挂起当前正在执行的线程对象,执行其他线程。2publicstaticvoidsleep(longmillisec)使当前正在执行的线程休眠(暂停执行)指定的毫秒数,这取决于系统计时器和调度程序的精度和准确性。3publicstaticbooleanholdsLock(Objectx)当且仅当当前线程持有指定对象上的监视器锁时才返回true。4publicstaticThreadcurrentThread()返回对当前正在执行的线程对象的引用。5publicstaticvoiddumpStack()将当前线程的堆栈跟踪打印到标准错误流。方法用法相同,请自行酌情使用。Runnable接口创建线程,因为它类似于Thread创建线程,所以我直接放代码。packageRunnable;importjava.time.LocalTime;publicclassRunnableDemoimplementsRunnable{@Overridepublicvoidrun(){//设置延迟try{for(inti=0;i<3;i++){Thread.sleep(1000);System.out.println(Thread.currentThread().getName()+"多线程输出"+LocalTime.now());}}catch(InterruptedExceptione){e.printStackTrace();}}}还有两个条件。实现Runnable和@Override运行。继承接口并重写run方法。Thread.currentThread().getName()返回当前调用的主线程的名称。跑步课有点不同。包可运行;publicclassRunnableTest{publicstaticvoidmain(String[]args){RunnableDemor=newRunnableDemo();线程t=新线程(r);t.开始();RunnableDemor1=newRunnableDemo();线程t1=新线程(r1);t1.开始();RunnableDemor2=newRunnableDemo();线程t2=新线程(r2);t2.start();}}//创建线程对象RunnableDemor=newRunnableDemo();//将线程对象放在Thread类对象中Threadt=newThread(r);//调用start方法t.start();运行结果是一样的。为什么要用Runnable,有人说,为什么这个东西多了一步,还很麻烦,我为什么不直接用Thread呢?我们首先要明白,Java语言是不允许多重继承的。两种实现方式最明显的区别在于,由于Java不允许多重继承,实现Runnable接口可以继承其他类,而Thread显然不能。Runnable可以实现同一个程序代码的多个线程共享同一个资源,Thread也不是不可以,但是和Runnable相比就不合适了。线程调度线程调度操作,常用的方法有以下几种。方法的作用intgetPriority()返回线程的优先级voidsetPrority(intnewPrority)改变线程的优先级booleanisAlive()判断线程是否活跃voidjoin()让进程中的其他线程等待该线程在运行前终止voidyield()挂起当前正在执行的线程对象,允许其他线程线程优先t.start();这样就可以设置线程对象的优先级,优先级有3个常量。MIN_PRIORITY//取值为最低1NORM_PRIORITY//取值为5正常级别MAX_PRIORITY//取值为10线程强制包Runnable;publicclassRunnableTest{publicstaticvoidmain(String[]args){RunnableDemor=newRunnableDemo();线程t=新线程(r);//线程强制运行//加入强制try{t.start();t.join();}catch(InterruptedExceptione){e.printStackTrace();}RunnableDemor1=newRunnableDemo();线程t1=新线程(r1);t1.开始();RunnableDemor2=newRunnableDemo();线程t2=新线程(r2);下载方法,大家自行查找。Thread礼貌yield是一个静态方法,类可以直接调用。注意!!!以上设置优先级不能完全控制,但是优先级越高,先跑的概率越高。yield的礼让也是一样,不是一定的,是增加概率,不是绝对的客气。而我们的join是绝对的线程同步首先我们要明白为什么要同步。为什么需要同步线程?安全问题?多线程执行的不确定性?执行结果不稳定?多个线程共享账本会导致操作不完整,破坏数据。当多线程访问共享数据时,可能会出现安全问题,例如:售票过程中出现重票、错票(以下多窗口售票demo存在多线程安全问题)。当票数为1时,三个线程中有一个线程被阻塞,不执行票数-1的操作。这是其他线程通过if语句的判断,会导致多卖一张票,会出现错误。票的情况。极端情况下,当票数为1时,三个线程同时判断通过,进入阻塞状态,然后在两边进行更多的卖票操作。所以,线程同步就是为了防止多个线程访问一个数据对象时造成数据损坏。那么线程同步的原因就解释清楚了。我必须准备一些代码来写一篇关于同步锁的文章。所以这篇文章先到这里!

猜你喜欢