线程的编程4种实现方法

线程的编程4种实现方法

1、继承Thread

Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。

public class Thread implements Runnable
@FunctionalInterface //函数式接口,其中包含一个抽象方法run 
public interface Runnable { 
public abstract void run();
}

启动线程的唯一方法就是通过Thread类的start()实例方法,不能直接调用run()方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法

class LeftThread extends Thread{
    for(int i=0;i<20;i++) {
        System.out.println("左手");
        try {//使当前正在执行的线程休眠等待500ms T
            hread.sleep(500); 
        } catch (InterruptedException e) { e.printStackTrace(); }
    }
}
}
//在主线程中启动这个线程 
Thread t1=new LeftThread(); 
t1.start();//不能直接调用run方法,否则就是在主线程中单线程执行,不是多线程

源代码阅读:

public class Thead implements Runnable{}线程类定义

重要属性

/* what will be run. */ 
private Runnable target;
}

粗略的阅读实现

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{
    public void run(){
        for(int i=0;i<50;i++)
        System.out.println("DDD");
    }
}

调用方法

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

2、实现Runnable接口

接口定义

@FunctionalInterface //函数式接口,简化定义方式为lambda表达式 
public interface Runnable{
public abstract void run();
}

可以使用lambda表示式进行定义,或者使用匿名内部类进行定义

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

使用lambda表达式的写法

//匿名内部类的写法
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();

3、使用Callable和Future接口创建线程###

具体是创建Callable接口的实现类,并实现call()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程

接口定义

Callable接口用于定义线程的执行逻辑

@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对象中,供线程执行对应call方法中的逻辑

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接口,所以new Thread(futureTask),当执行thread.start()方法时会自动调用Callable接口实现中的call方法。当调用futureTask.get()方法时可以获取对应的线程对象的执行结果,如果线程并没有返回时,当前线程阻塞等待

###4、使用线程池创建线程

享元模式

享元模式Flyweight Pattern主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式

优点:大大减少对象的创建,降低系统内存的使用,以提高程序的执行效率。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部 状态的变化而变化,否则会造成系统的混乱。

不考虑线程问题

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; 
 } 
   }   
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值