スレッドプログラミングを実現する4つの方法
1.スレッドを継承します
Threadクラスは基本的に、スレッドのインスタンスを表すRunnableインターフェイスのインスタンスを実装します。
public class Thread implements Runnable
@FunctionalInterface //函数式接口,其中包含一个抽象方法run
public interface Runnable {
public abstract void run();
}
スレッドを開始する唯一の方法は、Threadクラスのstart()インスタンスメソッドを使用することです。run()メソッドを直接呼び出すことはできません。start()メソッドはネイティブメソッドであり、新しいスレッドを開始してrun()メソッドを実行します。この方法でのマルチスレッド化は非常に簡単です。独自のクラスを介してThreadを直接拡張し、run()メソッドをオーバーライドして新しいスレッドを開始し、独自に定義したrun()メソッドを実行できます。
class LeftThread extends Thread{
public void run() {
for(int i=0;i<50;i++) {
System.out.println("左手一个慢动作...");
try {
//使当前正在执行的线程休眠等待500ms
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//在主线程中启动这个线程
Thread t1=new LeftThread();
t1.start();//不能直接调用run方法,否则就是在主线程中单线程执行,不是多线程
ソースコードの読み取り:
パブリッククラスTheadはRunnable {}スレッドクラス定義の
重要な属性を実装します
/* what will be run. */
private Runnable target;
インターフェイスメソッドの実装。定義をオーバーライドするときにメソッドシグネチャを変更することはできません。
public void run(){
if(target!=null)
target.run();
}
大まかな読み取りの実装
public synchronized void start() {
if (threadStatus != 0) //当前线程状态检查
throw new IllegalThreadStateException();
group.add(this); //将当前线程对象添加到一个线程组中进行管理
boolean started = false; //标志值用于判断当前线程是否已经启动
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();//通过对等类实现启动线程的细节,内部就是自动调用run()方法
スレッドクラスを定義する
class LeftThread extends Thread{
//定义左手线程类,只需要覆盖(重写)定义其中的run()方法,这里实际就是线程的执行线索,执行的程序
public void run(){
for(int i=0;i<50;i++)
System.out.println("左手一个慢动作....")
}
}
メソッドを呼び出す
Thread t1=new LeftThread();
t1.start();//启动线程必须使用start方法,而不能是调用run方法
//t1.run();不允许直接调用run方法,因为这种调用方式不是多线程,而是单线程
public class T4 {
public static void main(String[] args) {
new Thread() {
public void run() {
System.out.println("匿名类内部输出"+Thread.currentThread().getName());
}
}.run();//从语法上来说,可以直接调用run方法,但是运行run方法则不是多线程
//.start();输出结果证明不是main线程
System.out.println("main方法输出"+Thread.currentThread().getName());
}
}
スレッドの実行ステータスを判断する場合:
最简单的方式是查看线程个数
// Thread.currentThread()用于获取当前正在运行这个代码的线程对象
System.out.println(Thread.currentThread());
Thread t1 = new LeftThread();
// t1.run();在当前主线程中执行t1对象中的run方法
// t1.start();可以在LeftThread中获取到另外一个线程对象
public class LeftThread extends Thread {
@Override
public void run() {
// 这里包含的就是执行线索
System.out.println(Thread.currentThread());
}
}
最大の制限は、実際にはJavaのシングルルート継承システムです。これは基本的に不要です。
2.Runnableインターフェースを実装します
インターフェース定義
@FunctionalInterface //函数式接口,简化定义方式为lambda表达式
public interface Runnable{
public abstract void run();
}
ラムダ式を使用して定義するか、匿名内部クラスを使用して定義できます
class RightRunnable implements Runnable{
public void run(){
for(int i=0;i<50;i++)
System.out.println(Thread.currentThread().getName()+"说:右手慢动作重播!");
}
}
開始方法:
//启动通过实现Runnable接口定义的线程对象,不能直接使用Runnable r=new RightRunnable();
Thread t2=new Thread(new RightRunnable());
t2.start();
ラムダ式を使用する
//匿名内部类的写法
Thread t1 = new Thread(new Runnable() {
public void run() {
for(int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread() + "--" + i);
}
}
}); t1.start();
//lambda表达式的写法---要求接口必须是函数式接口
Thread t1 = new Thread(()-> {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread() + "--" + i);
}
}); t1.start();
static int sum=0;
public static void main(String[] args){
Thread t1=new Thread(){
public void run(){
for(int i=0;i<=100;i++)
sum+=i;
}
};
Thread t2=new Thread(new Runnable(){
public void run(){
for(int i=1;i<=100;i++)
sum+=i;
}
});
t2.start();
t1.start();
try{
Thread.currentThread().sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
}
プロセス内のパラメータの合計はプロセス内のすべてのスレッド(main \ t1 \ t2)で共有されるため、スレッドで共有されるコンテンツを介してデータを転送できますが、同時操作のため、計算結果が正しくない場合があります。
3.CallableおよびFutureインターフェースを使用してスレッドを作成します
@FuntionalInterface //属于函数式接口,所以可以直接使用lambda表达式进行定义
public interface Callable<V>{
//<>写法叫做泛型,用于定义返回的数据类型
V call()throws Exception;
}
Futureインターフェースは、Callableインターフェースのcallメソッドの実行結果に使用され、Callableの実行をテストできます。
public interface Future<V>{
//用于获取Callable接口中的call方法的执行结果
boolean cancel(boolean mayIntersupteIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException;
}
システムは、Futureインターフェースの実装クラスFutureTaskを提供します
public class FutureTask<V> implements RunnableFuture<V> //这个实现类实现了两个接口Runnable和 Future
FutureTaskクラスを使用すると、Callable実装をFutureTaskオブジェクトにカプセル化できます。同時に、FutureTaskはRunnableインターフェイスを実装するため、スレッドを実行するためのThreadクラスのコンストラクターパラメーターとしてThreadオブジェクトに渡すことができます。対応する呼び出しメソッドのロジック。
Callable<Integer> myCallable = new MyCallable(); // 创建MyCallable对象
FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装 MyCallable对象
Thread thread = new Thread(ft);//FutureTask对象作为Thread对象的target创建新的线程
thread.start(); //线程进入到就绪状态
int sum = ft.get(); //取得新创建的新线程中的call()方法返回的结果
使用法:
1。Callableインターフェースの実装クラスを定義します
public class MyCallable implements Callable<Integer>{
int begin=0;
int end=0;
public MyCallable(int begin, int end){
this.begin=begin;
this.end=end;
}
public Integer call()throws Exception{
int res=0;
for(int k=begin; k<=end; k++)
res+=k;
System.out.println(Thread.currentThread()+"---"+res);
return res;
}
}
2.電話する
FutureTask[] arr=new FutureTask[10];
for(int i=0;i<10;i++){
arr[i]=new FutureTask<>(new MyCallable(i*10+1,(i+1)*10));
Thread t=new Thread(arr[i]);
t.start();
}
int res=0;
for(int i=0;i<arr.length;i++)
res+=((Integer)arr[i].get());
System.out.println("计算结果为:"+res);
注:FutureTaskはFutureインターフェイスとRunnableインターフェイスを実装しているため、新しいThread(futureTask)は、thread.start()メソッドが実行されると、Callableインターフェイス実装のcallメソッドを自動的に呼び出します。futureTask.get()メソッドを呼び出すと、対応するスレッドオブジェクトの実行結果を取得できます。スレッドが戻らない場合は、現在のスレッドがブロックされて待機しています。
4.スレッドプールを使用してスレッドを作成します
フライ級モデル
Flyweightパターンは主に、作成されるオブジェクトの数を減らしてメモリ使用量を減らし、パフォーマンスを向上させるために使用されます。このタイプのデザインパターンは構造パターンであり、オブジェクトの数を減らして、アプリケーションに必要なオブジェクト構造を改善する方法を提供します。
利点:オブジェクトの作成を大幅に削減し、システムメモリの使用を削減して、プログラムの実行効率を向上させます。
短所:システムの複雑さが増し、外部状態と内部状態を分離する必要があります。外部状態には固有の性質があり、内部状態の変化に伴って変化してはなりません。そうしないと、システムに混乱が生じます。 。
スレッドの問題を考慮しないでください
public interface IShape {
void draw();
}
public class Circle implements IShape {
public void draw() {
System.out.println("我画一个圆");
}
}
インスタンスを取得するメソッドを提供するファクトリクラスを定義します
public class ShapeFactory {
private static IShape[] shapes = new IShape[20];
static{
for(int i=0;i<shapes.length;i++)
shapes[i]=new Circle();
}
public static IShape getShape() {
IShape res = null;
for (int i = shapes.length - 1; i >= 0; i--) {
res = shapes[i];
if (res != null) {
shapes[i]=null;
break;
}
}
return res;
}
public static void relaseShape(IShape circle) {
for (int i = 0; i < shapes.length; i++) {
IShape obj = shapes[i];
if (obj == null)
shapes[i] = circle;
}
}
}
ExecutorService、Callable、Futureを使用して、結果を返すスレッドを実装します。接続プールの具体的な実装は、実際にはThreadPoolExecutorに依存します。
//需要计算1+...+10000
public class T1 {
public static void main(String[] args) throws Exception {
// 创建一个固定大小的连接池,经常实现使用少量线程以应对波峰请求
ExecutorService es = Executors.newFixedThreadPool(3);
// 为了使用返回结果所以使用Callable
Future[] fs = new Future[10];
for (int i = 0; i < fs.length; i++) {
Callable<Integer> caller = new MyCallable(i * 1000 + 1, (i + 1) * 1000);
// 使用线程池执行任务并获取Future对象
fs[i]=es.submit(caller);
}
int res=0;
for(int i=0;i<fs.length;i++){
Object obj=fs[i].get();
if(obj!=null && obj instanceof Integer)
res+=(Integer)obj;
}
es.shutdown();//关闭线程池
System.out.println("Main:"+res);
}
}
class MyCallable implements Callable<Integer> {
private int begin;
private int end;
public MyCallable(int begin, int end) {
this.begin = begin;
this.end = end;
}
public Integer call() throws Exception {
System.out.println(Thread.currentThread()+"---"+begin+".."+end);
int res = 0;
for (int i = begin; i <= end; i++)
res += i;
return res;
}
}