Android多线程、多进程间的通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011976443/article/details/80221887

   1、 操作系统的任务调度

    在window和Linux操作系统中,任务调度采用时间片轮转机制,因为CPU执行效率非常高,内存执行效率比较低,为了提高CPU利用率,采用时间片轮转,就是一个任务执行一段时间之后强制暂停去执行下一个任务,每个任务轮流执行,被暂停的任务处于就绪状态,等待下一个属于它的时间片到来,这样每个任务都得到执行,而并发的意思就是多个任务同时执行。

    并行:是指多个处理器或者多核处理器同事处理多个不同的任务。

    并发:一个处理器同事处理多个任务。

       并发和并行与多线程的关系是:并行需要两个或者两个以上的线程运行在不同的处理器上,而并发可以再一个处理器上通过时间片轮转进行切换。

    2、进程线程定义

    操作系统负责任务调度,资源分配和管理,统领整个计算机硬件,应用程序则是具有某种功能的程序,运行于操作系统之上。

    进程:进程是具有独立功能的程序在一个数据集上的一次动态执行过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程一般由程序、数据集合、和进程控制块三部分组成。

    进程是程序的一次执行,是临时的有生命周期的,动态产生动态消亡,任何进程可以同其他进程一起并发执行,进程是系统进行资源分配和调度的独立单位,进程由程序,数据和控制块组成。

    线程:线程的作用简单来说是可以让进程中的不同代码块同时执行,线程是程序执行的单一顺序的控制流程,程序执行的最小单元,是处理器调度和分派的基本单位。各个线程之间共享进程的内存空间。一个线程由线程ID、当前指令指针PC、寄存器和堆栈组成。

    3、android中的多进程通信方法

    每个进程都对应虚拟机分配的一块独立的内存空间,不同的进程之间内存独立,(每个应用程序就是一个进程,当然一个应用程序可以有多个进程)如果两个进程之间需要共享数据,就需要用到IPC就是跨进程通信。

    Android的SDK提供四种跨进程通信方式,对应四大组件。Activity可以跨进程调用其他应用程序的Activity,content Provider可以跨进程访问其他应用程序的的数据,另外broadcast可以向系统所有应用发送广播,service之间可以通过AIDL实现进程间通信。

    (1)Activity:Activity跨进程不需要制定Context对象和Activity的class对象,需要访问的是Activity所对赢得action,和URI,是Intent的第二个参数。

    如:Intent callIntent = new Intent(Intent.ACTION_CALL,Uri.parse(“tel:123456”));

           startActivity(callIntent);

    (2)ContentProvider

     Android应用程序需可以使用文件或者Sqlite共享存储数据,可以利用contentProvider进行增删查改,如音频、视频、联系人信息、通过这些ContentProvider可以获取相应的信息列表,这些列表以Cursor对象返回。

    (3)广播

    发送广播需要调用sendBroadcast方法,该方法需要一个Intent对象,通过Intent可以发送,广播需要的数据,利用广播通信会有明显的延时,并且因为广播是向整个操作系统发送,容易出现被其他应用程序拦截的情况。

    (4)service

    service既不是线程也不是进程,如果需要执行耗时操作,需要新开一个线程实现,这个时候可以使用IntentService实现,因为IntentService总的HandAction实际上是一个线程可以处理耗时操作。

    使用AIDL实际上是CS架构,这个时候如果需要反馈数据,需要进行两边同时定义AIDL接口,然后进行数据的回传。

4、AIDL通信

    实现AIDL通信对于需要传递一个自定义对象的数据,需要序列化,序列化分为两种方法Serializable和Parcelable。

    4.1序列化的目的:

    (1)永久保存对象数据,将对象保存在文件或磁盘中

    (2)通过序列化将对象数据,进行网络传输,把对象数据转换为字节流方式

    (3)将对象数据在进程间进行传递,在当前Activity中进行序列化操作写入,在另一个中进行反序列化操作读出。

    (4)将数据保存至数据库和文件中

    (5)序列化只针对对象不针对方法

    (6)Intent之间传递数据,复杂的可以使用序列化操作。

    4.2 android中实现序列化两种方法。

    (1)Serialization接口

写一个实体类 Person,利用Java自带的Serializable进行序列化

package com.amqr.serializabletest.entity;
import java.io.Serializable;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 14:16
 * Describe: Describe Text
 */
public class Person implements Serializable{
    private static final long serialVersionUID = 7382351359868556980L;
    private String name;
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

使用,MainActivity和SecondActivity结合使用

MainActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.amqr.serializabletest.entity.Person;
/**
 * 进行Android开发的时候,我们都知道不能将对象的引用传给Activities或者Fragments,
 * 我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。
 *
 *
 * Android中Intent如果要传递类对象,可以通过两种方式实现。
 * 方式一:Serializable,要传递的类实现Serializable接口传递对象,
 * 方式二:Parcelable,要传递的类实现Parcelable接口传递对象。
 *
 * Serializable(Java自带):
 * Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
 *
 * Parcelable(android 专用):
 * 除了Serializable之外,使用Parcelable也可以实现相同的效果,
 * 不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,
 * 而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
 要求被传递的对象必须实现上述2种接口中的一种才能通过Intent直接传递。
 */
public class MainActivity extends Activity {
    private TextView mTvOpenNew;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.mTvOpenNew).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent open = new Intent(MainActivity.this,SecondActivity.class);
                Person person = new Person();
                person.setName("一去二三里");
                person.setAge(18);
                // 传输方式一,intent直接调用putExtra
                // public Intent putExtra(String name, Serializable value)
                open.putExtra("put_ser_test", person);
                // 传输方式二,intent利用putExtras(注意s)传入bundle
                /**
                Bundle bundle = new Bundle();
                bundle.putSerializable("bundle_ser",person);
                open.putExtras(bundle);
                 */
                startActivity(open);
            }
        });
    }
}

SecondActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
import com.amqr.serializabletest.entity.Person;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 11:56
 * Describe: Describe Text
 */
public class SecondActivity extends Activity{
    private TextView mTvDate;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        mTvDate = (TextView) findViewById(R.id.mTvDate);
        Intent intent = getIntent();
        // 关键方法:getSerializableExtra ,我们的类是实现了Serializable接口的,所以写这个方法获得对象
        // public class Person implements Serializable
        Person per = (Person)intent.getSerializableExtra("put_ser_test");
        //Person per = (Person)intent.getSerializableExtra("bundle_ser");
        mTvDate.setText("名字:"+per.getName()+"\\n"
                +"年龄:"+per.getAge());
    }
}
链接:https://www.jianshu.com/p/a60b609ec7e7

    (2)Parcelable接口

我们写一个实体类,实现Parcelable接口,马上就被要求

1、复写describeContents方法和writeToParcel方法

2、实例化静态内部对象CREATOR,实现接口Parcelable.Creator 。

也就是,随便一个类实现了Parcelable接口就一开始就会变成这样子

Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。

public class Pen implements Parcelable{
    private String color;
    private int size;
    protected Pen(Parcel in) {
        color = in.readString();
        size = in.readInt();
    }
    public static final Creator<Pen> CREATOR = new Creator<Pen>() {
        @Override
        public Pen createFromParcel(Parcel in) {
            return new Pen(in);
        }
        @Override
        public Pen[] newArray(int size) {
            return new Pen[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(color);
        dest.writeInt(size);
    }
}

系统已经帮我们做了很多事情,我们需要做的很简单,就写写我们自己需要的构造方法,写一下私有变量的get和set

大概变成这样子:

package com.amqr.serializabletest.entity;
import android.os.Parcel;
import android.os.Parcelable;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 14:52
 * Describe: Describe Text
 */
public class Pen implements Parcelable{
    private String color;
    private int size;
    
    // 系统自动添加,给createFromParcel里面用
    protected Pen(Parcel in) {
        color = in.readString();
        size = in.readInt();
    }
    public static final Creator<Pen> CREATOR = new Creator<Pen>() {
        /**
         *
         * @param in
         * @return
         * createFromParcel()方法中我们要去读取刚才写出的name和age字段,
         * 并创建一个Person对象进行返回,其中color和size都是调用Parcel的readXxx()方法读取到的,
         * 注意这里读取的顺序一定要和刚才写出的顺序完全相同。
         * 读取的工作我们利用一个构造函数帮我们完成了
         */
        @Override
        public Pen createFromParcel(Parcel in) {
            return new Pen(in); // 在构造函数里面完成了 读取 的工作
        }
        //供反序列化本类数组时调用的
        @Override
        public Pen[] newArray(int size) {
            return new Pen[size];
        }
    };
    
    @Override
    public int describeContents() {
        return 0;  // 内容接口描述,默认返回0即可。
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(color);  // 写出 color
        dest.writeInt(size);  // 写出 size
    }
    // ======分割线,写写get和set
    //个人自己添加
    public Pen() {
    }
    //个人自己添加
    public Pen(String color, int size) {
        this.color = color;
        this.size = size;
    }
    
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
}

其实说起来Parcelable写起来也不是很麻烦,在as里面,我们的一个实体类写好私有变量之后,让这个类继承自Parcelable,接下的步骤是:

1、复写两个方法,分别是describeContents和writeToParcel

2、实例化静态内部对象CREATOR,实现接口Parcelable.Creator 。 以上这两步系统都已经帮我们自动做好了

3、自己写写我们所需要的构造方法,变量的get和set

实现自Parcelable实体Bean已经写好了,接下来我们结合MainActivity和ThirdActivity来使用以下:

MainActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.amqr.serializabletest.entity.Pen;
import com.amqr.serializabletest.entity.Person;
/**
 * 进行Android开发的时候,我们都知道不能将对象的引用传给Activities或者Fragments,
 * 我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。
 *
 *
 * Android中Intent如果要传递类对象,可以通过两种方式实现。
 * 方式一:Serializable,要传递的类实现Serializable接口传递对象,
 * 方式二:Parcelable,要传递的类实现Parcelable接口传递对象。
 *
 * Serializable(Java自带):
 * Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
 *
 * Parcelable(android 专用):
 * 除了Serializable之外,使用Parcelable也可以实现相同的效果,
 * 不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,
 * 而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
 要求被传递的对象必须实现上述2种接口中的一种才能通过Intent直接传递。
 */
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.mTvOpenNew).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent open = new Intent(MainActivity.this, SecondActivity.class);
                Person person = new Person();
                person.setName("一去二三里");
                person.setAge(18);
                // 传输方式一,intent直接调用putExtra
                // public Intent putExtra(String name, Serializable value)
                open.putExtra("put_ser_test", person);
                // 传输方式二,intent利用putExtras(注意s)传入bundle
                /**
                 Bundle bundle = new Bundle();
                 bundle.putSerializable("bundle_ser",person);
                 open.putExtras(bundle);
                 */
                startActivity(open);
            }
        });
        // 采用Parcelable的方式
        findViewById(R.id.mTvOpenThird).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent mTvOpenThird = new Intent(MainActivity.this,ThirdActivity.class);
                Pen tranPen = new Pen();
                tranPen.setColor("big red");
                tranPen.setSize(98);
                // public Intent putExtra(String name, Parcelable value)
                mTvOpenThird.putExtra("parcel_test",tranPen);
                startActivity(mTvOpenThird);
            }
        });
    }
}

ThirdActivity

package com.amqr.serializabletest;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import com.amqr.serializabletest.entity.Pen;
/**
 * User: LJM
 * Date&Time: 2016-02-22 & 14:47
 * Describe: Describe Text
 */
public class ThirdActivity extends Activity{
    private TextView mTvThirdDate;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);
        mTvThirdDate = (TextView) findViewById(R.id.mTvThirdDate);
//        Intent intent = getIntent();
//        Pen pen = (Pen)intent.getParcelableExtra("parcel_test");
        Pen pen = (Pen)getIntent().getParcelableExtra("parcel_test");
        mTvThirdDate = (TextView) findViewById(R.id.mTvThirdDate);
        mTvThirdDate.setText("颜色:"+pen.getColor()+"\\n"
                            +"大小:"+pen.getSize());
    }
}
链接:https://www.jianshu.com/p/a60b609ec7e7

(3)性能比较

    parcelable性能强于serializable

    (1)内存使用中强于后者

    (2)后者序列化操作时候,会产生大量临时变量,从而导致GC频繁调用,性能下降

    (3)parcelable是以Ibinder为载体,内存上开销较小。

    (4)读写数据的时候parcelable是直接读写,而serializable是通过IO流形式读写如硬盘上。

当然在将数据持久化的时候,如把数据写入硬盘的时候,仍然需要使用serializable。

4.3创建一个简单的AIDL实例

首先,我们就在AS里面新建一个aidl文件(ps:现在AS建aidl不要求和java包名相同了):

package aidl;
interface IMyInterface {
    String getInfor(String s);
}

可以看到,在这里面我们就一个方法getInfor(String s),接受一个字符串参数,然后返回一个字符串,相当的简单。

接着你sync project一下就可以在app/generated/source/aidl/debug/aidl里面发现由aidl文件生成的java文件了。点进去一看,可能你也被这个的类给吓住了,那现在我们就先不管它了。

然后就看看Service:

public class MyService extends Service { 

public final static String TAG = "MyService";

private IBinder binder = new IMyInterface.Stub() {
        @Override       
        public String getInfor(String s) throws RemoteException { 
            Log.i(TAG, s); 
            return "我是 Service 返回的字符串"; 
       }
    };
@Overrid
public void onCreate() {
    super.onCreate(); 
    Log.i(TAG, "onCreat");    
}       
@Override    
public IBinder onBind(Intent intent) { 
    return binder;  
    }
}

       这里我们写了一个Service,看一下也比较简单。先new了一IMyInterface.Stub()并把它向上转型成了IBinder,最后在onBind方法中返回回去。可能你注意到了,在IMyInterface.Stub()的内部我们重写getInfor(String s) 方法,没错这就是我们 aidl文件中定义的接口。 
       对了,因为我们希望看到的是跨进程通信,所以我们把MyService定义成新启动一个进程:

<service
    android:name=".server.MyService"
    android:process="com.xu.remote" />

        定义为启动在新进程中,只需要在AndroidMainfest.xml中声明是加上一个process属性即可,不过这里有两个地方值得注意: 
1.组件默认的进程名就是包名; 
2.定义新的进程名的时候需要以包的形式(eg: com.xu.aidl)。

接着,我们继续向下看:

public class MainActivity extends AppCompatActivity {
    public final static String TAG = "MainActivity";
    private IMyInterface myInterface;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myInterface = IMyInterface.Stub.asInterface(service);
            Log.i(TAG, "连接Service 成功");
            try {
                String s = myInterface.getInfor("我是Activity传来的字符串");
                Log.i(TAG, "从Service得到的字符串:" + s);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "连接Service失败");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startAndBindService();
    }
    private void startAndBindService() {
        Intent service = new Intent(MainActivity.this, MyService.class);
        //startService(service);
        bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
    }
}

在onCreate(Bundle savedInstanceState)中,我们调用了自己定义的一个方法startAndBindService(),这个方法里面我们生成了一个Intent,然后 bindService了这个Intent传入了三个参数分别是Intent、ServiceConnection、Flag。

Intent我们就不用说了,我们看看后面两个参数: 
在Activity中,我们new了一个ServiceConnection并实现了他的两个方法onServiceConnected、onServiceDisconnected。在onServiceConnected中我们通过IMyInterface.Stub.asInterface(service)把传来的IBinder转换成了我们定义的IMyInterface。然后我们调用了getInfor方法,传递了个字符串和获取从MyService传来的字符串,并且打印了Log。

对于我们传的Context.BIND_AUTO_CREATE的意思就是说:如果绑定Service的时候,Service还没有被创建,就创建它。

    大致的实现流程就是,先定义一个AIDL接口,然后进行再service中的stub中实现接口中的方法,然后在client中实现通过ServiceConnection连接,并且在asInterface中调用方法。

    4.4 aidl中的接口解析

    Binder工作机制由客户端、Binder、服务端组成,客户端和服务端都是通过Binder进行交流。

    Stub类是继承自Binder类,Stub类就是Binder的实例,在服务端一般会实例化一个Binder对象,客户端在Service中绑定的时候可以获取这个Stub(Binder)

通过asInterface()方法获取它的实例对象。如果客户端和服务端在同一进程下,那么asInterface()将返回Stub对象本身,否则返回Stub.Prox对象。

也就是说asInterface()返回的对象有两种可能(实际上有三种,还有一种是null),Stub和Stub.Proxy。它们有什么区别呢?

  1. 如果在同一个进程下的话,那么asInterface()将返回服务端的Stub对象本身,因为此时根本不需要跨进称通信,那么直接调用Stub对象的接口就可以了,返回的实现就是服务端的Stub实现,也就是根本没有跨进程通信;

  2. 如果不是同一个进程,那么asInterface()返回是Stub.Proxy对象,该对象持有着远程的Binder引用,因为现在需要跨进程通信,所以如果调用Stub.Proxy的接口的话,那么它们都将是IPC调用,它会通过调用transact方法去与服务端通信。

  3. Stub是服务端实现的存根,而Proxy则是Stub的代理。

5、多线程实现方法

    java实现多线程实现方式主要有四种:继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器创建Thread线程、使用ExecutorService、Callble、Future实现有返回结果的多线程。

    (1)继承Thread类创建线程

    Thread本质上是实现Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,他启动一个新县城,并执行run()方法。直接继承Thread,然后重写run()方法启动新线程即可执行自定义的run()方法。

    public class MyThread extends Thread{

        public void run(){

            //逻辑

        }

    }

MyThead myThead1 = new MyThread();

MyThread myThread2 = new MyThread();

myThread1.start();

myThread2.start();


(2)实现Runnable 接口创建线程

如果自己已经extends一个类,就无法直接extends Thread ,此时可以实现一个Runnable接口:

    public class MyThread extends OhterClass implements Runnable{

        public void run(){

            //逻辑

        }

    }

MyThread myThread = new MyThread();

Thread thread  = new Thread(myThread);

thread.start();


(3)实现Callable接口通过FutureTask包装器来创建爱你Thread线程

     Callable接口定义:

public class SomeCallable<V> extends OtherClass implements Callable<V> {

    @Override
    public V call() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

}
复制代码
复制代码
Callable<V> oneCallable = new SomeCallable<V>();   
//由Callable<Integer>创建一个FutureTask<Integer>对象:   
FutureTask<V> oneTask = new FutureTask<V>(oneCallable);   
//注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。 
  //由FutureTask<Integer>创建一个Thread对象:   
Thread oneThread = new Thread(oneTask);   
oneThread.start();   
//至此,一个线程就创建完成了。
复制代码

4、使用ExecutorService、Callable、Future实现有返回结果的线程

      ExecutorService、Callable、Future三个接口实际上都是属于Executor框架。返回结果的线程是在JDK1.5中引入的新特征,有了这种特征就不需要再为了得到返回值而大费周折了。而且自己实现了也可能漏洞百出。

      可返回值的任务必须实现Callable接口。类似的,无返回值的任务必须实现Runnable接口。

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。

注意:get方法是阻塞的,即:线程无返回结果,get方法会一直等待。

再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。

下面提供了一个完整的有返回结果的多线程测试例子,在JDK1.5下验证过没问题可以直接使用。代码如下:

复制代码
import java.util.concurrent.*;  
import java.util.Date;  
import java.util.List;  
import java.util.ArrayList;  
  
/** 
* 有返回值的线程 
*/  
@SuppressWarnings("unchecked")  
public class Test {  
public static void main(String[] args) throws ExecutionException,  
    InterruptedException {  
   System.out.println("----程序开始运行----");  
   Date date1 = new Date();  
  
   int taskSize = 5;  
   // 创建一个线程池  
   ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
   // 创建多个有返回值的任务  
   List<Future> list = new ArrayList<Future>();  
   for (int i = 0; i < taskSize; i++) {  
    Callable c = new MyCallable(i + " ");  
    // 执行任务并获取Future对象  
    Future f = pool.submit(c);  
    // System.out.println(">>>" + f.get().toString());  
    list.add(f);  
   }  
   // 关闭线程池  
   pool.shutdown();  
  
   // 获取所有并发任务的运行结果  
   for (Future f : list) {  
    // 从Future对象上获取任务的返回值,并输出到控制台  
    System.out.println(">>>" + f.get().toString());  
   }  
  
   Date date2 = new Date();  
   System.out.println("----程序结束运行----,程序运行时间【"  
     + (date2.getTime() - date1.getTime()) + "毫秒】");  
}  
}  
  
class MyCallable implements Callable<Object> {  
private String taskNum;  
  
MyCallable(String taskNum) {  
   this.taskNum = taskNum;  
}  
  
public Object call() throws Exception {  
   System.out.println(">>>" + taskNum + "任务启动");  
   Date dateTmp1 = new Date();  
   Thread.sleep(1000);  
   Date dateTmp2 = new Date();  
   long time = dateTmp2.getTime() - dateTmp1.getTime();  
   System.out.println(">>>" + taskNum + "任务终止");  
   return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";  
}  
}  
复制代码

 

代码说明:
上述代码中Executors类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads) 
创建固定数目线程的线程池。
public static ExecutorService newCachedThreadPool() 
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newSingleThreadExecutor() 
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

参考:https://www.cnblogs.com/felixzh/p/6036074.html

https://blog.csdn.net/baidu_29094221/article/details/78852998

https://blog.csdn.net/yan8024/article/details/6444368

https://blog.csdn.net/aboy123/article/details/38307539/

https://blog.csdn.net/wangchunlei123/article/details/51345130

https://www.cnblogs.com/yezhennan/p/5527506.html

大致就写到这里吧,知识越扩展越多,本人技术小白一个,有错误地地方,多多指点。

猜你喜欢

转载自blog.csdn.net/u011976443/article/details/80221887