Thread类重写run();Runnable类重写run();Callable类重写call();实现线程的方式

实现线程的方式

1.继承Thread类重写run();

Thread类中常用的两个构造方法是:
    public Thread();//无参构造
    public Thread(String threadName);//有参构造

完成线程真正功能的代码放在类的run()方法中,当一个类继承Thread类后,就可以在该类中覆盖run()方法,
将实现该功能的代码写入run()方法中,然后调用Thread类中的start()方法执行线程,等价于调用run()方法;
其中,Thread类不可以重复启动一个线程,也就是说,不可以调用已经启动的线程。强行调用,会抛出异常IllegalTreadStateException。

2.实现Runnable接口重写run();

实际上,Thread类实现了Runnable接口,其中的run()方法就是对Runnable接口中的run()方法的具体实现。
实现Runnable接口的程序会创建一个Thread对象,并将Runnable对象和Thread对象相关联。适合多个相同的程序代码的线程去处理同一个资源。

Thread类有以下两个构造方法:使用这两个方法就可以将Runnable和Thread两个实例相关联。
  public Thread(Runnable target);/traget是目标的意思
  public Thread(Runnable target,String name);

使用Runnable接口启动线程的步骤:
  建立Runnable对象;
  使用参数为Runnable对象的构造方法创建Thread实例;
  调用start()方法启动线程;
说到这里你可能也不明白怎么整,所以,请看下面的代码:
RET.java
package com;

public class RET implements Runnable {

    private static int ticket = 10;
    public RET() {

    }

    @Override
    public void run() {//防止线程抢占资源
        while(ticket>0) {
            synchronized("") {//这样也行,定义锁也行,目前我还没发现这两种的区别,待定!!!!
                if(ticket>0) {
                    System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"张票");
                    --ticket;
                }else {
                    System.out.println("票卖完了");
                }
            }
        }
    }
}

App.java

package com;

public class App {

    public App() {
        RET r1 = new RET();
        RET r2 = new RET();
        
        new Thread(r1).start();
        new Thread(r2).start();
        new Thread(r2).start();//可以调用已经启动的线程,虽然可以这样,但是这条线程算是第三条线程了。不过不建议这样用,因为很混乱。
    }
    public static void main(String[] args) {
        new App();
    }
}
其中,如果一个类继承Thread,就不可以资源共享。但是如果实现了Runable接口的话,就可以实现资源共享。说到共享资源,就一定会抢占资源!要加锁!
而且,无论是继承Thread还是实现Runnable都不可以给方法加锁eg:public synchronized void run() {//防止线程抢占资源 因为这样加锁顶不住!!
都要static Object lock="locked";//这样加锁!!!!在改变数据的时候要synchronized(lock){在这里改变数据}!!!!

3.实现Callable接口重写call();

Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。

  Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能

  Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。

步骤:

  自定义一个类实现java.util.concurrent包下的Callable接口
  重写call方法
  将要在线程中执行的代码编写在call方法中
  创建ExecutorService线程池
  将自定义类的对象放入线程池里面
  获取线程的返回结果
  关闭线程池,不再接收新的线程,未执行完的线程不会被关闭

看代码:

call.java

package com;

import java.util.concurrent.Callable;

public class call implements Callable<String> {//定义一个类实现Callable<V>接口
    private static int ticket = 10;
    private Object lock = "";
    public call() {
        
    }

    @Override
    public String call() throws Exception {
        while(ticket>0) {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName()+"第"+ticket+"张");
                --ticket;
            }
        }
        return "没错,我执行完了上面的代码,还告诉你我完事了。";
    }

}

App.java

package com;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class App {

    public App() {
        //创建ExecutorService线程池
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //创建存储Future对象,用来存放ExecutorService的执行结果
        Future<String> future = threadPool.submit(new call());
        try {
            System.out.println("等待线程结束");
            System.out.println(future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
       threadPool.shutdown();

    }
  } 
  public static void main(String[] args) {
    
new App();
  }
}


但是,线程池怎么可能只放一个线程呢??请看多个线程的办法,就是存到了数组里

cable.java
package com;

import java.util.concurrent.Callable;

public class cable implements Callable<String> {//定义一个类实现Callable<V>接口
    private  int a,b;
    public cable(int a,int b) {
        this.a=a;
        this.b=b;
    }

    @Override
    public String call() throws Exception {
        System.out.println(a+b+" "+Thread.currentThread().getName());
        Thread.sleep(1000);
        return "没错,我执行完了上面的代码,还告诉你我完事了。";
    }

}
App.java
package com;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class App {

    public App() throws InterruptedException, ExecutionException {
        //创建ExecutorService线程池
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //创建存储Future对象的集合,用来存放ExecutorService的执行结果
         ArrayList<Future<String>> future = new ArrayList<Future<String>>();
        //举例子:开3个线程,将返回的Future对象放入集合中
        future.add(threadPool.submit(new cable(1,2)));
        future.add(threadPool.submit(new cable(4,5)));
        future.add(threadPool.submit(new cable(7,8)));
        
        for (Future<String> fs : future) {
            //判断线程是否执行结束,如果执行结束就将结果打印
            if (fs.isDone()) {
                System.out.println("22222"+fs.get());
            } else {
                System.out.println("44444"+fs.toString());
            }
        }
        //关闭线程池,不再接收新的线程,未执行完的线程不会被关闭
        threadPool.shutdown();
        System.out.println("main方法执行结束");
    }
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        new App();
    }
}

猜你喜欢

转载自www.cnblogs.com/cattree/p/10659634.html