共计 4812 个字符,预计需要花费 13 分钟才能阅读完成。
过程和线程
~ 线程是在一个过程中,并发执行的多个程序逻辑,线程是过程执行的单位。
~ 一个过程中至多有一个线程,而这个线程被称为主线程,主线程是一个程序的入口,main 就是由主线程来执行的。
线程创立三种形式:
1. 继承 Thread 类
2. 实现 Rnnable 接口
3. 实现 Callable 接口
继承 Thread
public class thread extends Thread{
@Override
public void run() {for (int i = 0; i < 20; i++) {System.out.println("这是 run 线程"+i);
}
}
public static void main(String[] args) {
// 开启 run 线程 start 是同时运行 run 办法是先执行 run 办法 在执行主线程
thread thread = new thread();
thread.start();// 开启线程
for (int i = 0; i < 200; i++) {System.out.println("这是 main 线程"+i);
}
}
}
实现 Rnnable 接口
public class runnable implements Runnable{
@Override
public void run() {for (int i = 0; i < 20; i++) {System.out.println("这是 run 线程"+i);
}
}
public static void main(String[] args) {runnable runnable = new runnable();// 创立线程对象
new Thread(runnable,"定义线程名").start();// 须要一个 Thread 对象
for (int i = 0; i < 200; i++) {System.out.println("这是 main 线程"+i);
}
}
}
实现 Callable 接口
public class callable implements Callable<Object> {
@Override
public Object call() throws Exception {Object object = new Object();
return object;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创立线程
callable callable = new callable();
// 创立执行服务
ExecutorService pool = Executors.newFixedThreadPool(3);
// 执行线程 获取后果
Future<Object> res = pool.submit(callable);
Object obj = res.get();
// 敞开服务
pool.shutdownNow();}
}
~ run 办法和 start 办法两者是有区别的,run 会先运行 run 里代码在运行主线程,start 是同时运行。
~ 线程开启并不一定立刻执行,是由 cpu 调度的,人为无奈干涉。
~ 获取以后线程的名字
Thread.currentThread().getName();
~ 获取线程的状态
State state = thread.getState();
线程的五种状态
- 初始状态 new 当创立了一个线程时,会进入此状态。
- 就绪状态 当初始状态调用了 start()办法时,会进入此状态。
- 运行状态 当就绪状态的线程取得 cpu 工夫片,即调度到它,进入运行状态。
- 梗塞状态 当调用 sleep,wait 办法或同步锁定,线程进入梗塞,代码不往下执行,梗塞事件完结后从新进入 * 就绪状态,期待 cpu 调度。
终止状态 线程中断或者执行完所有代码,进入终止状态。
synchronized 隐式锁
synchronize 有两种时用,同步办法,同步代码块。synchronize 同步办法默认锁的时 this,即以后对象,同步代码块能够锁任何对象。死锁线程单方锁了对方所须要的临界资源,导致单方都处于梗塞状态。
同步代码块:
synchronized (obj){//obj 须要锁的对象}
lock 显示锁
不同于 synchronize(修饰符),lock 是可重入锁,是一个对象,他只能锁代码块,由 jdk1.5 推出的新个性,lock 已本身为标记,代替了临界资源互斥锁标记。
创立 lock 锁:
private final ReentrantLock lock = new ReentrantLock(); // 创立 lock 锁对象
try{lock.lock(); // 加锁
...
}finally{lock.unlock(); // 解锁
}
线程之间的通信
~ 线程间的通信 须要临界资源来调用相应的办法 因为锁标记是临界资源所领有的
wait():当临界资源调用 wait() 办法时 以后线程 放弃工夫片 放弃互斥锁标记 进入期待区(进入阻塞状态)
notify():当临界资源调用 notify()时会依据肯定策略 唤醒期待区中的某个线程 该线程从新回归就绪状态
notifyAll():当临界资源调用 notifyAll()时 唤醒期待区中的所有线程 所有线程进入就绪状态
sleep()和 wait()区别
它俩来自不同的类,sleep()是 Thread 类的,wait()是来自于 Object 类。
sleep() 只让出了 CPU,却不会开释对象锁,处于梗塞状态,它须要设置休眠工夫。wait()会放弃对象锁,并让出 cpu 资源,处于期待状态,应用 notify()和 notifyAll()来唤醒。
sleep() 会抛出 InterruptedException 异样,须要进行相干解决,而 wait()不须要捕捉异样。
线程平安的汇合
CopyOnWriteArrayList:所在包 java . util . concurrent;读操作远远大于写操作时,效率高,在写时会先创立正本将写操作进行结束时,再替换原容器,保障读的正确性,但写的效率很低。
ConcurrentHashMap : 所在包 java . util . concurrent;进步了 HashMap 的并发效率,应用了分级锁,将本来的 hash 表分,成了 16 段,一个 hash 表时,有一个线程操作任意一个地位,都会导致 hash 被锁,但分成了 16 段加锁时,一个线程拜访一部分时,其余线程能够拜访其余局部。
线程池
~ 顾名思义,一个池子用来装线程的容器,可已设定线程调配数量下限,将事后创立线程对象存入池中,并重用线程池中的线程。
~ 益处是缩小创立和销毁线程的次数。
线程池的根本接口:Executor
线程池接口:ExecutorService
线程池工具类:Executors,用于创立线程。
newSingleThreadPool 创立一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有工作。如果这个惟一的线程因为异样完结,那么会有一个新的线程来代替它,此线程池保障所有工作的执行程序依照工作的提交程序执行。
public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {public void run() {
try {System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {e.printStackTrace();
}
}
});
}
}
}
newFixedThreadPool 创立固定大小的线程池。每次提交一个工作就创立一个线程,直到线程达到线程池的最大大小。某个线程因为执行异样而完结,那么线程池会补充一个新线程。
public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {public void run() {
try {System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {e.printStackTrace();
}
}
});
}
}
}
newCachedThreadPool 创立一个可缓存的线程池。如果线程池的大小超过了解决工作所须要的线程,那么就会回收局部变量(60 秒不执行工作)的线程,当工作数减少时,此线程池又能够智能的增加新线程来解决工作。此线程池不会对线程池大小做限度,线程池大小齐全依赖于操作系统(或者说 JVM)可能创立的最大线程大小。
public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {Thread.sleep(index * 1000);
} catch (InterruptedException e) {e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {public void run() {System.out.println(index);
}
});
}
}
}
newScheduledThreadPool 创立一个定长的线程池,而且反对定时的以及周期性的工作执行,反对定时及周期性工作执行。
public class ThreadPoolExecutorTest {public static void main(String[] args) {ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {public void run() {System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}
应用
public static void main(String[] args) {
// 创立线程工作对象
MyRunnable02 mr=new MyRunnable02();
// 获取线程池对象
ExecutorService es=Executors.newFixedThreadPool(2);
// 调用办法执行线程工作
es.submit(mr);
es.submit(mr);
// 销毁线程池
es.shutdown();}
最初
欢送关注公众号:前程有光,支付一线大厂 Java 面试题总结 + 各知识点学习思维导 + 一份 300 页 pdf 文档的 Java 外围知识点总结!这些材料的内容都是面试时面试官必问的知识点,篇章包含了很多知识点,其中包含了有基础知识、Java 汇合、JVM、多线程并发、spring 原理、微服务、Netty 与 RPC、Kafka、日记、设计模式、Java 算法、数据库、Zookeeper、分布式缓存、数据结构等等。