2024-03-30 04:15:06 | 我爱编程网
在 Java 中,线程(Thread)是指程序执行的一条路径,是进程中的一个实体。Java 中的线程是轻量级的,可以同时运行多个线程,这就是多线程(Multithreading)。
多线程是指在一个程序中同时运行多个线程,每个线程都可以独立执行不同的任务。多线程的特点包括:
提高程序的并发性:多线程可以让程序同时执行多个任务,提高程序的并发性,从而提高程序的效率。
提高程序的响应性:多线程可以让程序在执行耗时操作时不会阻塞,从而提高程序的响应性,使用户能够更快地得到反馈。
充分利用 CPU 资源:多线程可以让程序充分利用 CPU 资源,提高 CPU 的利用率,从而提高程序的效率。
方便处理复杂的任务:多线程可以让程序同时处理多个复杂的任务,从而方便处理复杂的任务。
需要注意的是,多线程也会带来一些问题,例如线程安全问题、死锁问题等,因此在编写多线程程序时需要注意这些问题。
线程定义比较抽象,简单的说就是一个代码执行流。许多执行流可以混合在一起由CPU调度。线程是允许各种任务交互执行的方式。
Java的线程在操作系统的实现模式依系统不同而不同,可能是系统级别的进程或线程,但对于程序员来说并没有影响。
任务交互的一个好处是增加程序响应。如一个界面程序执行一段耗时的数据库查询,使用单独的线程可以让界面依然响应用户的其他输入,而单线程只能等待查询结束再处理。
JVM以及操作系统会优先处理优先级别高的线程,但不代表这些线程一定会先完成。设定优先级只能建议系统更快的处理,而不能强制。
另外,在运行时,并没有按照函数分界,而是按照机器码/汇编码分界。也就是说不保证任何一段代码是被完整而不打断的执行的(除非你已经使用同步手段)。正由于如此,各种线程同步的方法应运而生。
我爱编程网(https://www.52biancheng.com)小编还为大家带来RxJava怎么实现多个线程同时执行,怎么实现retryWhen的相关内容。
在编写一个类时,如果该类中的代码可能运行于多线程环境下,那么就要考虑同步的问题,Java实现线程同步的方法很多,具体如下。
(1)synchronized关键字
在Java中内置了语言级的同步原语synchronized关键字,其在多线程条件下实现了对共享资源的同步访问。根据synchronized关键字修饰的对象不同可以分为以下几种情况。
*synchronized关键字同步方法
public synchronized void method(){
//do something
}
注意: 如果使用synchronized关键字同步方法,很容易误认为同步关键字锁住了它所包围的代码。但是实际情况却不是这样,同步加锁的是对象而并非代码。因此。如果在一个类中有一个同步方法,该方法是可以被两个不同的线程同时执行的,只要每个线程自己创建一个该类的实例即可。
示例代码:
package newthread;
public class TestSync {
public static void main(String[] args) {
MyThread1 my1=new MyThread1(1);
MyThread1 my2=new MyThread1(3);
my1.start();
my2.start();
}
}
class MyThread1 extends Thread{
private int val;
public MyThread1(int v){
val=v;
}
public synchronized void printVal(int v){
for(int i=0;i<100;i++){
System.out.print(v);
}
}
public void run(){
printVal(val);
}
}
执行代码结果是1和3交叉输出的,即1和3两个线程在并发执行printVal方法,并没有实现同步功能。原因在于synchronized关键字锁定的是对象而并非代码块,如果需要实现真正的同步,必须同步一个全局对象或者对类进行同步。synchronized关键字同步类的格式如下:
synchronized(MyThread.class){}
改进代码
package newthread;
public class TestSync_2 {
public static void main(String[] args) {
MyThread_2 my1=new MyThread_2(1);
my1.start();
MyThread_2 my2=new MyThread_2(2);
my2.start();
}
}
class MyThread_2 extends Thread{
private int val;
public MyThread_2(int v){
val=v;
}
public void printVal(int v){
synchronized(MyThread_2.class){
for(int i=0;i<100;i++){
System.out.print(v);
}
}
}
public void run(){
printVal(val);
}
}
在上面的实例中,printVal()方法的功能不再对个别的类实行同步,而是对当前类进行同步。对于MyThread而言,它只有惟一的类定义,两个线程在相同的锁上同步,因此在同一时刻只有一个线程可以执行printVal()方法。至于输出结果的两种可能,则是由于Java线程调度的抢占实现模式所决定的。
*synchronized关键字同步公共的静态成员变量
在上面的示例中,通过对当前类进行加锁,达到了线程同步的效果,但是基于线程同步的一般原理是应该尽量减小同步的粒度以达到更高的性能。其实针对上文中的示例,也可以通过对公共对象加锁,即添加一个静态成员变量来实现,两种方法都通过同步该对象而达到线程安全。示例代码如下:
package newthread;
public class TestSync_3 {
public static void main(String[] args) {
MyThread_3 my1=new MyThread_3(2);
my1.start();
MyThread_3 my2=new MyThread_3(5);
my2.start();
}
}
class MyThread_3 extends Thread{
private int val;
private static Object lock=new Object();
public MyThread_3(int v){
val=v;
}
public void printVal(int v){
synchronized(lock){
for(int i=0;i<100;i++){
System.out.print(v);
}
}
}
public void run(){
printVal(val);
}
}
注意:为了能够提高程序的性能,针对示例代码中对于对象的选取做一个简单的介绍:基于JVM的优化机制,由于String类型的对象是不可变的,因此当用户使用“”的形式引用字符串时,如果JVM发现内存已经有一个这样的对象,那么它就使用该对象而不再生成一个新的String对象,这样是为了减小内存的使用;而零长度的byte数组对象创建起来将比任何对象要实用,生成零长度的byte[]对象只需要3条操作码,而Object lock=new Object()则需要7行操作码。
*synchronized关键字同步游离块
synchronized{
//do something
}
synchronized关键字同步代码块和上文中所提到的synchronized关键字同步公共的静态成员变量类似,都是为了降低同步粒度避免对整个类进行同步而极大降低了程序的性能
*synchronized关键字同步静态方法
public synchronized static void methodAAA(){
//do something
}
public void methodBBB(){
synchronized(Test.class){
//do something
}
}
synchronized关键字同步静态方法与synchronized关键字同步类实现的效果相同,唯一不同的是获得的锁对象不同,当同一个object对象访问methodAAA()和methodBBB()时,同步静态方法获得的锁就是该object类,而同步类方法获得的对象锁则是object对象所属的那个类
(2)Metux互斥体的设计和使用
Metux称为互斥体,同样广泛应用于多线程编程中。。其中以Doug Lea教授编写的concurrent工具包中实现的Mutex最为典型,本文将以此为例,对多线程编程中互斥体的设计和使用做简单介绍。在Doug Lea的concurrent工具包中,Mutex实现了Sync借口,该接口是concurrent工具包中所有锁(lock)、门(gate)、和条件变量(condition)的公共接口,SyncD的实现类主要有Metux、Semaphore及其子类、Latch、CountDown和ReentrantLock等。这也体现了面向对象抽象编程的思想,使开发者可以在不改变代码或者改变少量代码的情况下,选择使用Sync的不同实现。Sync接口的定义如下:
package newthread;
public interface Sync {
//获取许可
public void acquire() throws InterruptedException;
//尝试获取许可
public boolean attempt(long msecs)throws InterruptedException;
//释放许可
public void realse();
}
通过使用Sync接口可以替代synchronized关键字,并提供更加灵活的同步控制,但是并不是说concurrent工具包是独立于synchronized的技术,其实concurrent工具包也是在synchronized的基础上搭建的。区别在于synchronized关键字仅在方法内或者代码块内有效,而使用Sync却可以跨越方法甚至通过在对象之间传递,跨越对象进行同步。这是Sync及concurrent工具包比直接使用synchronized更加强大的地方。
需要注意的是Sync中的acquire()和attempt()方法都会抛出InterruptedException异常,因此在使用Sync及其子类时,调用这些方法一定要捕获InterruptedException。而release()方法并不会抛出InterruptedException异常,这是因为在acquire()和attemp()方法中都有可能会调用wait()方法等待其他线程释放锁。因此,如果对一个并没有acquire()方法的线程调用release()方法不会存在什么问题。而由于release()方法不会抛出InterruptedException,因此必须在catch或finally子句中调用release()方法以保证获得的锁能够被正确释放。示例代码如下:
package newthread;
public class TestSync_4 {
Sync gate;
public void test(){
try {
gate.acquire();
try{
//do something
}finally{
gate.realse();
}
} catch (InterruptedException ex) {
}
}
}
Mutex是一个非重入的互斥锁。广泛应用于需要跨越方法的before or after类型的同步环境中。下面是一个Doug Lea的concurrent工具包中的Mutex的实现,代码如下:
package newthread;
import com.sun.corba.se.impl.orbutil.concurrent.Sync;
public class TestMutex implements Sync{
protected boolean flg=false;
public void acquire() throws InterruptedException {
if(Thread.interrupted())
throw new InterruptedException;
synchronized(this){
try{
while(flg)
wait();
flg=true;
}catch(InterruptedException ex){
notify();
throw ex;
}
}
}
public boolean attempt(long msecs) throws InterruptedException {
if(Thread.interrupted())
throw new InterruptedException;我爱编程网
synchronized(this){
if(!flg){
flg=true;
return true;
}else if(msecs<=0){
return false;
}else{
long waitTime=msecs;
long start=System.currentTimeMillis();
try{
for(;;){
wait(waitTime);
if(!flg){
flg=true;
return true;
}else{
waitTime=msecs-(System.currentTimeMillis()-start);
if(waitTime<=0)
return false;
}
}
}catch(InterruptedException ex){
notify();
throw ex;
}
}
}
}
public void release() {
flg=false;
notify();
}
}
Python多线程是什么意思?简单地说就是作为可能是仅有的支持多线程的解释型语言(perl的多线程是残疾,PHP没有多线程),Python的多线程是有compromise的,在任意时间只有一个Python解释器在解释Pythonbytecode。UPDATE:如评论指出,Ruby也是有thread支持的,而且至少RubyMRI是有GIL的。如果你的代码是CPU密集型,多个线程的代码很
php怎样多线程操作其实就PHP而言,可以用2种方式来做:(1)在PHP里使用shell_exec的函数,以shell的方式,启动一个独立的PHP脚本执行。这种方式,其实相当于在Web服务器处理过程中,独立起了一个shell进程处理你的任务。这里,需要特别注意的是shell_exec的服务器安全,注意校验参数,小心避免被带入shell命令中。这个是比较容易实现的方式。(2)使用PHP
用Java实现多线程有哪些途径?1,创建Thread类的子类在这个途径中,用户程序需要创建自己的Thread类的子类,并在子类中重新定义自己的run()方法,这个run()方法中包含了用户线程的操作。这样在用户程序需要建立自己的线程时,它只需要创建一个已定义好的Thread子类的实例就可以了。例:publicclassTestThread{...(中间的就不写了)}c
python中文叫什么python中文叫什么?python中文叫蟒蛇,通常情况下,Python是一种计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。Python在设计上坚持了清晰划一的风格,这使得Python成为一门易读、易维护,并且被大量用户所欢迎的、用
RxJava怎么实现多个线程同时执行,怎么实现retryWhen在编写一个类时,如果该类中的代码可能运行于多线程环境下,那么就要考虑同步的问题,Java实现线程同步的方法很多,具体如下。(1)synchronized关键字在Java中内置了语言级的同步原语synchronized关键字,其在多线程条件下实现了对共享资源的同步访问。根据synchronized关键字修饰的对象不同可以分
用来编写JAVA程序的应用软件有哪些,都叫什么1、Eclipse-IBM甩出来给开源社区的IDE,其本身就是使用Java开发的。2、MyEclipse-把Eclipse包装了一下,加了J2EE企业开发的许多功能强大的插件。3、NetBeans-SUN公司自己开发的Java开发环境,功能挺多的。4、还有一些超喜欢手工编写Java代码的牛人喜欢使用带语法着色功能的纯文本编辑器
为数组的每个元素应用回调函数?数组的4种声明方式:1.先声明再初始化例如://1.声明int[]nums;//初始化nums=newint[5];2.声明并初始化例如://2.声明、初始化int[]nums=newint[10];3.创建数组同时赋值例如://3.创建数组同时赋值String[]names=newString[]{"大
java获取运行时间很多朋友都想知道java怎么获取运行时间?下面就一起来了解一下吧~第一种是以毫秒为单位计算的。//伪代码long startTime=System.currentTimeMillis(); //获取开始时间doSomeThing(); //测试的代码段long endTime=System.currentTimeMillis(); //获取结束时间System.
2025-02-01 20:24:39
2024-01-05 14:11:24
2025-02-12 03:21:37
2025-02-10 15:19:48
2025-01-28 17:58:32
2024-11-22 05:08:01