首页 > 后端开发 > 正文

RxJava怎么实现多个线程同时执行,怎么实现retryWhen

2024-04-13 05:00:28 | 我爱编程网

小编今天整理了一些RxJava怎么实现多个线程同时执行,怎么实现retryWhen相关内容,希望能够帮到大家。

本文目录一览:

RxJava怎么实现多个线程同时执行,怎么实现retryWhen

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();

}

}

RxJava怎么实现多个线程同时执行,怎么实现retryWhen

如何确保JAVA程序在一台机器上不能同时运行两个实例

最简单的方法是在程序运行起来后创建一个临时文件(或在文件中写入一个运行标志),每次运行程序前读取这个文件,如果这个文件存在(或运行标志已经设置),说明有该程序已经运行着一个实例;但要注意在程序退出前确保删除这个文件。

还有一种方法是调用jdk内置的jps命令($JAVA_HOME/bin/jps),这个命令可以查看当前运行着的java程序及运行参数。比如你的程序的运行方式如下

java -cp app.jar com.example.Main

调用

jps -l

可以得到类似如下输出

<进程id> com.example.Main

可以通过判断输出是否存在程序的入口类来判断程序是否已经运行。

RxJava怎么实现多个线程同时执行,怎么实现retryWhen

java 多线程是什么?一个处理器怎么同时处理多个程序

进程是程序在处理机中的一次运行。一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立。所以进程是重量级的任务,它们之间的通信和转换都需要操作系统付出较大的开销。

线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。所以线程是轻量级的任务,它们之间的通信和转换只需要较小的系统开销。

Java支持多线程编程,因此用Java编写的应用程序可以同时执行多个任务。Java的多线程机制使用起来非常方便,用户只需关注程序细节的实现,而不用担心后台的多任务系统。

Java语言里,线程表现为线程类。Thread线程类封装了所有需要的线程操作控制。在设计程序时,必须很清晰地区分开线程对象和运行线程,可以将线程对象看作是运行线程的控制面板。在线程对象里有很多方法来控制一个线程是否运行,睡眠,挂起或停止。线程类是控制线程行为的唯一的手段。一旦一个Java程序启动后,就已经有一个线程在运行。可通过调用Thread.currentThread方法来查看当前运行的是哪一个线程。

class ThreadTest{

public static void main(String args[]){

Thread t = Thread.currentThread();

t.setName("单线程"); //对线程取名为"单线程"

t.setPriority(8);

//设置线程优先级为8,最高为10,最低为1,默认为5

System.out.println("The running thread: " + t);

// 显示线程信息

try{

for(int i=0;i<3;i++){

System.out.println("Sleep time " + i);

Thread.sleep(100); // 睡眠100毫秒

}

}catch(InterruptedException e){// 捕获异常

System.out.println("thread has wrong");

}

}

}

多线程的实现方法

继承Thread类

可通过继承Thread类并重写其中的run()方法来定义线程体以实现线程的具体行为,然后创建该子类的对象以创建线程。

在继承Thread类的子类ThreadSubclassName中重写run()方法来定义线程体的一般格式为:

public class ThreadSubclassName extends Thread{

public ThreadSubclassName(){

..... // 编写子类的构造方法,可缺省

}

public void run(){

..... // 编写自己的线程代码

}

}

用定义的线程子类ThreadSubclassName创建线程对象的一般格式为:

ThreadSubclassName ThreadObject =

new ThreadSubclassName();

然后,就可启动该线程对象表示的线程:

ThreadObject.start(); //启动线程

应用继承类Thread的方法实现多线程的程序。本程序创建了三个单独的线程,它们分别打印自己的“Hello World!”。

class ThreadDemo extends Thread{

private String whoami;

private int delay;

public ThreadDemo(String s,int d){

whoami=s;

delay=d;

}

public void run(){

try{

sleep(delay);

}catch(InterruptedException e){ }

System.out.println("Hello World!" + whoami

+ " " + delay);

}

}

public class MultiThread{

public static void main(String args[]){

ThreadDemo t1,t2,t3;

t1 = new ThreadDemo("Thread1",

(int)(Math.random()*2000));

t2 = new ThreadDemo("Thread2",

(int)(Math.random()*2000));

t3 = new ThreadDemo("Thread3",

(int)(Math.random()*2000));

t1.start();

t2.start();

t3.start();

}

}

实现Runnable接口

编写多线程程序的另一种的方法是实现Runnable接口。在一个类中实现Runnable接口(以后称实现Runnable接口的类为Runnable类),并在该类中定义run()方法,然后用带有Runnable参数的Thread类构造方法创建线程。

创建线程对象可用下面的两个步骤来完成:

(1)生成Runnable类ClassName的对象

ClassName RunnableObject = new ClassName();

(2)用带有Runnable参数的Thread类构造方法创建线程对象。新创建的线程的指针将指向Runnable类的实例。用该Runnable类的实例为线程提供 run()方法---线程体。

Thread ThreadObject = new Thread(RunnableObject);

然后,就可启动线程对象ThreadObject表示的线程:

ThreadObject.start();

在Thread类中带有Runnable接口的构造方法有:

public Thread(Runnable target);

public Thread(Runnable target, String name);

public Thread(String name);

public Thread(ThreadGroup group,Runnable target);

public Thread(ThreadGroup group,Runnable target,

String name);我爱编程网

其中,参数Runnable target表示该线程执行时运行target的run()方法,String name以指定名字构造线程,ThreadGroup group表示创建线程组。

用Runnable接口实现的多线程。

class TwoThread implements Runnable{

TwoThread(){

Thread t1 = Thread.currentThread();

t1.setName("第一主线程");

System.out.println("正在运行的线程: " + t1);

Thread t2 = new Thread(this,"第二线程");

System.out.println("创建第二线程");

t2.start();

try{

System.out.println("第一线程休眠");

Thread.sleep(3000);

}catch(InterruptedException e){

System.out.println("第一线程有错");

}

System.out.println("第一线程退出");

}

public void run(){

try{

for(int i = 0;i < 5;i++){

System.out.println(“第二线程的休眠时间:”

+ i);

Thread.sleep(1000);

}

}catch(InterruptedException e){

System.out.println("线程有错");

}

System.out.println("第二线程退出");

}

public static void main(String args[]){

new TwoThread();

}

}

程序运行结果如下:

正在运行的线程: Thread[第一主线程,5,main

创建第二线程

第一线程休眠

第二线程的休眠时间:0

第二线程的休眠时间:1

第二线程的休眠时间:2

第一线程退出

第二线程的休眠时间:3

第二线程的休眠时间:4

第二线程退出

至于一个处理器同时处理多个程序,其实不是同时运行多个程序的,简单的说,如果是单核的CPU,在运行多个程序的时候其实是每个程序轮流占用CPU的,只是每个程序占用的时间很短,所以我们人为的感觉是“同时”运行多个程序。

以上就是我爱编程网小编为大家带来的内容了,想要了解更多相关信息,请关注我爱编程网。
与“RxJava怎么实现多个线程同时执行,怎么实现retryWhen”相关推荐