线程和进程
进程是一个正在运行的程序实例,一个进程下面有许多线程。不同的进程有不同的内存空间,同一进程下的所有线程共享进程的堆 和方法区资源,每个线程有自己的程序计数器,虚拟机栈和本地方法栈。线程更轻量,切换成本更低。
jdk1.2之前Java 线程是基于绿色线程(Green Threads)实现的,这是一种用户级线程(用户线程),之后Java 线程改为基于原生线程(Native Threads)实现,也就是说 JVM 直接使用操作系统原生的内核级线程(内核线程)来实现 Java 线程,由操作系统内核进行线程的调度和管理。
并行和并发
并行是指在同一时刻进行,并发是指在同一时间段进行
同步和异步
- 同步:发出一个调用之后,在没有得到结果之前, 该调用就不可以返回,一直等待。
- 异步:调用在发出之后,不用等待返回结果,该调用直接返回。
死锁
死锁就是双方互相持有对方需要的资源,并且不释放自己的资源,导致所有线程永久阻塞,无法继续进行
线程创建的方式
创建多线程的方式有继承Thread,重写callable,重写Runnable,线程池创建。
-
生产环境首选:线程池(处理异步 / IO / 并发请求);
-
需返回结果时:Callable+FutureTask(并发计算、拆分任务);
-
简单解耦场景:Runnable(避免单继承);
-
几乎不用:继承 Thread (单继承限制,无复用)。
javaimport java.util.concurrent.*; class MyThread1 extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName()+"->我正在以继承Thread的方式运行"); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } class MyThread2 implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()+"->我正在以重写Runnable的方式运行"); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } class MyThread3 implements Callable<Integer> { private int num; public MyThread3(int num) { this.num = num; } @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+"->我正在以重写callable方式运行"); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } return num; } } /* Runnable 没有返回值,只能在内部消化异常不能往上抛 Callable有返回值,需要用futuretask获得返回结果,允许抛出异常。 */ class MyThread4 { static ExecutorService threadPool = Executors.newFixedThreadPool(5); public static void main(String[] args) { for(int i=1;i<=5;i++){ threadPool.submit(()->{ System.out.println(Thread.currentThread().getName()+"->以线程池的方式进行"); }); } } } /* newFixedThreadPool(n):固定核心线程数,适用于任务量稳定的场景; newCachedThreadPool():弹性线程池,按需创建线程,空闲 60s 销毁; newSingleThreadExecutor():单线程池,任务串行执行; newScheduledThreadPool(n):定时 / 周期性任务线程池。 */ public class ThreadPractice { public static void main(String[] args) { MyThread1 thread11=new MyThread1(); MyThread1 thread12=new MyThread1(); thread11.setName("thread11"); thread12.setName("thread12"); thread11.start(); thread12.start(); MyThread2 myThread2=new MyThread2(); Thread thread21=new Thread(myThread2,"thread21"); Thread thread22=new Thread(myThread2,"thread22"); thread21.start(); thread22.start(); MyThread3 myThread31=new MyThread3(1314); MyThread3 myThread32=new MyThread3(520); FutureTask<Integer> futureTask2=new FutureTask<Integer>(myThread31); FutureTask<Integer> futureTask1=new FutureTask<Integer>(myThread32); new Thread(futureTask2).start(); new Thread(futureTask1).start(); } }
- start() vs run() :
start():触发 JVM 创建新线程,调用run(),只能调用 1 次(多次调用抛IllegalThreadStateException);run():普通方法,直接调用不会创建新线程,主线程执行。
- 线程安全 :多个线程操作共享变量时会出现问题(比如计数错乱),后续可练习
synchronized、Lock解决; - 线程状态:新建(New)→ 就绪(Runnable)→ 运行(Running)→ 阻塞(Blocked/Waiting/Timed Waiting)→ 终止(Terminated);
- 常用 API :
Thread.sleep(long ms):让当前线程休眠(不释放锁);Thread.yield():让出 CPU,线程回到就绪状态;join():等待线程执行完成(比如thread1.join(),主线程等 thread1 执行完)。
线程的状态
Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态:
- NEW: 初始状态,线程被创建出来但没有被调用
start()。 - RUNNABLE: 运行状态,线程被调用了
start()等待运行的状态。 - BLOCKED:阻塞状态,需要等待锁释放。
- WAITING:等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)。
- TIME_WAITING:超时等待状态,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
- TERMINATED:终止状态,表示该线程已经运行完毕。

锁
乐观锁和悲观锁
乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源(也就是数据)是否被其它线程修改了(具体方法可以使用版本号机制或 CAS 算法)。
悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程。
先发布吧 后面怎么写我再想想