Java多线程与并发


1、进程和线程的区别

进程和线程的由来

  • 串行:初期的计算机智能串行执行任务,并且需要长时间等待用户输入
  • 批处理:预先将用户的指令集中成清单,批量串行处理用户指令.仍然无法并发执行
  • 进程:进程独占内存空间。保存各自运行状态,相互间不干扰且可以互相切换,为并发处理任务提供了可能
  • 线程:共享进程的内存资源。相互间切换更快速,支持更细粒度的任务控制,使进程内的子任务得以并发执行

进程是资源分配的最小单位,线程是CPU调度的最小单位

  • 所有与进程相关的资源,都被记录在PCB中
  • 进程是抢占处理机的调度单位;线程属于某个进程,共享其资源

  • 线程只由堆栈寄存器、程序计数器和TCB组成

总结

  • 线程不能看做独立应用,而进程可看做独立应用
  • 进程有独立的地址空间,相互不影响,线程只是进程的不同执行路径
  • 线程没有独立的地址空间,多进程的程序比多线程程序健壮
  • 进程的切换比线程的切换开销大

Java进程和线程的关系

  • Java对操作系统提供的功能进行封装,包括进程和线程
  • 运行一个程序会产生一个进程,进程包含至少-个线程
  • 每个进程对应一个JVM实例,多个线程共享JVM里的堆
  • Java采用单线程编程模型,程序会自动创建主线程
  • 主线程可以创建子线程,原则上要后于子线程完成执行

java是具有主线程的:

public class CurrentThreadDemo {
    public static void main(String[] args) {
        System.out.println("Current Thread: " + Thread.currentThread().getName());
    }
}

2、Thread中的start和run方法的区别

  • 调用start()方法会创建一个新的子线程并启动
  • run()方法只是Thread的一 个普通方法的调用

示例代码:

public class ThreadTest {
    private static void attack() {
        System.out.println("Fight");
        System.out.println("Current Thread is : " + Thread.currentThread().getName());
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(){
            public void run(){
                attack();
            }
        };
        System.out.println("current main thread is : " + Thread.currentThread().getName());
        t.run();  // min
        t.start();  // Thread-0
    }
}

运行结果:

current main thread is : main
Fight
Current Thread is : main
Fight
Current Thread is : Thread-0

使用start是调用外部类:

openjdk网页中查找源码(链接🔗):


Tread.c文件中查找start0,发现引入了jvm文件,再去查询对应的方法(链接🔗):

3、Thread和Runnable是什么关系

  • Thread是实现了 Runnable接口的类,使得run支持多线程
  • 因类的单一继承原则,推荐多使用Runnable接口

示例代码:

  • Thread示例
    public class MyThread extends Thread {
      private String name;
      public MyThread(String name){
          this.name = name;
      }
      @Override
      public void run(){
          for(int i = 0 ; i < 10 ; i ++){
              System.out.println("Thread start : " + this.name + ",i= " + i);
          }
      }
    }
    Thred主类:
    public class ThreadDemo {
      public static void main(String[] args) {
          MyThread mt1 = new MyThread("Thread1");
          MyThread mt2 = new MyThread("Thread2");
          MyThread mt3 = new MyThread("Thread3");
          mt1.start();
          mt2.start();
          mt3.start();
      }
    }
    运行结果:
    Thread start : Thread1,i= 0
    Thread start : Thread3,i= 0
    Thread start : Thread3,i= 1
    Thread start : Thread2,i= 0
    Thread start : Thread3,i= 2
    Thread start : Thread1,i= 1
    Thread start : Thread2,i= 1
    Thread start : Thread3,i= 3
    Thread start : Thread2,i= 2
    ......
  • Runnable示例
    public class MyRunnable implements Runnable {
      private String name;
      public MyRunnable(String name){
          this.name = name;
      }
      @Override
      public void run(){
          for(int i = 0 ; i < 10 ; i ++){
              System.out.println("Thread start : " + this.name + ",i= " + i);
          }
      }
    }
    Runable主类
    public class RunnableDemo {
      public static void main(String[] args) throws InterruptedException {
          MyRunnable mr1 = new MyRunnable("Runnable1");
          MyRunnable mr2 = new MyRunnable("Runnable2");
          MyRunnable mr3 = new MyRunnable("Runnable3");
          Thread t1 = new Thread(mr1);
          Thread t2 = new Thread(mr2);
          Thread t3 = new Thread(mr3);
          t1.start();
          t2.start();
          t3.start();
      }
    }
    运行结果:
    Thread start : Runnable2,i= 0
    Thread start : Runnable3,i= 0
    Thread start : Runnable3,i= 1
    Thread start : Runnable1,i= 0
    Thread start : Runnable1,i= 1
    Thread start : Runnable1,i= 2
    ......

如何给run()方法传参(研究一下)

实现的方式主要有三种

  • 构造函数传参
  • 成员变量传参
  • 回调函数传参

如何实现处理线程的返回值

实现的方式主要有三种

  • 主线程等待法

    实现简单,但是需要自己实现循环等待的逻辑,当需要等待的变量越多,代码将显得越臃肿,没法进行精准控制
  • 使用Thread类的join()阻塞当前线程以等待子线程处理完毕

    比上一个方法简单,但是粒度不够细,

    示例代码:

    public class CycleWait implements Runnable{
      private String value;
      public void run() {
          try {
              Thread.currentThread().sleep(5000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          value = "we have data now";
      }
    
      public static void main(String[] args) throws InterruptedException {
          CycleWait cw = new CycleWait();
          Thread t = new Thread(cw);
          t.start();
          // 如果没有以下两种方法,则在线程执行是先打印value值,而不是先等待线程然后赋值,导致程序一运行打印value:null
          /* 主线程等待法,需要判断线程实例中的valu是否为空,当为空的时候等待100毫秒,直到线程完成,最后打印 */
          while (cw.value == null){
              Thread.currentThread().sleep(100);
          }
          /* 阻塞当前线程以等待子线程处理完毕,最后打印 */
    //        t.join();
          System.out.println("value : " + cw.value);
      }
    }

    运行结果:

    value : we have data now
  • 通过Callable接口实现:通过FutureTask Or线程池获取

示例代码:

Callable接口实现

import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception{
        String value="test";
        System.out.println("Ready to work");
        Thread.currentThread().sleep(5000);
        System.out.println("task done");
        return value;
    }
}
  • 通过FutureTask获取
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class FutureTaskDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<String>(new MyCallable());
        new Thread(task).start();
        if(!task.isDone()){
            System.out.println("task has not finished, please wait!");
        }
        System.out.println("task return: " + task.get());
    }
}

运行结果:

task has not finished, please wait!
Ready to work
task done
task return: test
  • 通过线程池获取
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        Future<String> future = newCachedThreadPool.submit(new MyCallable());
        if(!future.isDone()){
            System.out.println("task has not finished, please wait!");
        }
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            newCachedThreadPool.shutdown();
        }
    }
}

运行结果:

task has not finished, please wait!
Ready to work
task done
test

评论
评论