日常记录——多线程与高并发—线程概念以及创建线程的五种方式

概念

  1. 进程:一个程序的运行资源。
  2. 线程:进程里面最小的资源执行单元,即一个程序里不同的执行单元。
  3. 纤程/协程:更牛逼的东西,轻量级线程,一个线程可以创建任意多个纤程。

线程的创建方式

1.继承Thread类
创建一个类继承Thread类,重写run()方法,调用创建对象的start()方法,该start()方法表示先开启线程。

public class Thread {
     
    public static void main(String[] args) {
         
        Thread.currentThread().setName("主线程");
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        //创建一个新线程
        ThreadDemo thread = new ThreadDemo();
        //为线程设置名称
        thread.setName("线程一");
        //开启线程
        thread.start();
    }
}
 
class ThreadDemo extends Thread{
     
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
    }
     
}

2. 实现Runnable接口
创建一个类并实现Runnable接口,重写run()方法,创建实现Runnable接口的类的对象,将该对象当做Thread类的构造方法中的参数传进去,使用Thread类的构造方法创建一个对象,并调用start()方法即可开启该线程。

public class Thread {
     
    public static void main(String[] args) {
        Thread.currentThread().setName("主线程");
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        //创建一个新线程
        Thread thread = new Thread(new ThreadDemo());
        //为线程设置名称
        thread.setName("线程二");
        //开启线程
        thread.start();
    }
     
}
 
class ThreadDemo implements Runnable {
 
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
    }
     
}

3. 实现Callable接口
创建一个类并实现Callable接口,重写call()方法,将所要完成的任务的代码写进call()方法中,需要注意的是call()方法有返回值,并且可以抛出异常,如果想要获取运行该线程后的返回值,需要创建Future接口的实现类的对象,即FutureTask类的对象,调用该对象的get()方法可获取call()方法的返回值,使用Thread类的有参构造器创建对象,将FutureTask类的对象当做参数传进去,然后调用start()方法开启并运行该线程。

public class Thread {
     
    public static void main(String[] args) throws Exception {
        Thread.currentThread().setName("主线程");
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        //创建FutureTask的对象
        FutureTask<String> task = new FutureTask<String>(new ThreadDemo());
        //创建Thread类的对象
        Thread thread = new Thread(task);
        thread.setName("线程三");
        //开启线程
        thread.start();
        //获取call()方法的返回值,即线程运行结束后的返回值
        String result = task.get();
        System.out.println(result);
         
    }
     
}
 
class ThreadDemo implements Callable<String> {
 
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        return Thread.currentThread().getName()+":"+"返回的结果";
    }
}

4. 使用线程池创建
Java通过Executors提供四种线程池,分别为:
1.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
以newFixedThreadPool 为例:使用Executors类中的newFixedThreadPool(int num)方法创建一个线程数量为num的线程池,调用线程池中的execute()方法执行由实现Runnable接口创建的线程;调用submit()方法执行由实现Callable接口创建的线程,调用线程池中的shutdown()方法关闭线程池。

public class Thread {
     
    public static void main(String[] args) throws Exception {
         
        Thread.currentThread().setName("主线程");
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        //通过线程池工厂创建线程数量为2的线程池
        ExecutorService service = Executors.newFixedThreadPool(2);
        //执行线程,execute()适用于实现Runnable接口创建的线程
        service.execute(new ThreadDemoRunnable());
        service.execute(new ThreadDemoRunnable());
        service.execute(new ThreadDemoRunnable());
        //submit()适用于实现Callable接口创建的线程
        Future<String> task = service.submit(new ThreadDemoCallable());
        //获取call()方法的返回值
        String result = task.get();
        System.out.println(result);
        //关闭线程池  停止接收新的的任务,已经提交的任务(包括正在跑的和队列中等待的),会继续执行完成;
        service.shutdown();
    }
}
//实现Runnable接口
class ThreadDemoRunnable implements Runnable{
     
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
    }
     
}
//实现Callable接口
class ThreadDemoCallable implements Callable<String>{
 
    @Override
    public String call() throws Exception {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":"+"输出的结果");
        return Thread.currentThread().getName()+":"+"返回的结果";
    }
 
}

注意!请注意!!!*
FixedThreadPool和SingleThreadPool的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。CachedThreadPool,ScheduledThreadPool允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。虽说正常情况下,不会堆积大量请求,但还是推荐自己使用ThreadPoolExecutor构造线程池。

5. 使用@Async注解创建多线程
使用@Async注解创建线程非常的方便,而且在使用上跟普通方法没什么区别,加上个@Async注解即可实现异步调用。

@Component
public class AsyncTask {
 @Async
 public void register(){
 System.out.println("线程开始");
 try {
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 System.out.println("线程结束");
 }
}
@RestController
@RequestMapping(value = "/async")
public class AsyncTaskController {
 @Autowired
 private AsyncTask asyncTask;
 @GetMapping(value = "/test")
 public Object test(){
 for (int i = 0; i < 10; i++) {
 asyncTask.register();
 }
 System.out.println("主线程结束");
 return "OK";
 }
}

启用Async需要添加@EnableAsync注解

@SpringBootApplication
@ServletComponentScan
@EnableAsync
public class App {
 public static void main(String[] args) {
 SpringApplication.run(App.class, args);
 }
}

猜你喜欢

转载自blog.csdn.net/weixin_43001336/article/details/106953050