选择JDK8、JDK11进行讲解的原因:Oracle长期支持
进程和线程的由来
进程是资源分配的最小单位,线程是cpu调度的最小单位.
进程是资源分配的基本单位,所有与进程有关的资源都记录在进程控制块PCB中,以表示进程拥有这些资源或者正在使用它们,进程也是抢占处理机的调度单位,它拥有完整的虚拟内存地址空间,当进程发生调度时,不同的进程拥有不同的地址空间,而同一进程内的不同线程共享同一地址空间。与进程相对应,线程与资源分配无关,它属于某一个进程,并与进程内的其它线程共享进程的资源。
总结:
获取当前线程名称:
System.out.println("Current Thread: "+Thread.currentThread().getName());
创建一个新线程
public class Test {
private static void attack() {
System.out.println("Current Thread is :" + Thread.currentThread().getName());
}
public static void main(String[] args) {
Thread t = new Thread() {
// 新线程run()需要执行的内容
public void run() {
attack();
}
};
System.out.println("main Thread :" + Thread.currentThread().getName());
// 调用start方法,开启新线程
t.start();
}
}
结果:
main Thread :main
Fight
Current Thread is :Thread-0
Thread是一个类,实现了Runnable接口
我们可以打开其源码,发现Thread类实现了Runnable接口,进入Runnable接口发现其中只有一个抽象的run方法,也就说明了这个接口并不具备多线程的特性,是依赖Thread中的start的方法去创建一个子线程,再在子线程中调用一个thread实现好了的run方法去执行相应的业务逻辑.才能让类具备多线程的特性。
Thread
public class Thread implements Runnable {
public synchronized void start() {
}
}
Runnable
public interface Runnable{
public abstract void run( );
}
Thread和 Runnable是什么关系
也就是线程需要执行,需要run( )方法,也就是新建线程的执行逻辑。还需要start( )方法,调用系统创建多线程的方法。也就是 start( )方法让系统创建一个新的线程执行run( )方法中逻辑。
extends Thread:内部有继承的run( )方法和start( )方法。可以自己执行。
implement Runnable:内部只有run( )方法。需要调用Thread中的start ( )才能执行。
继承Thread方式(extends Thread)
自定义线程类:
public class MyThread extends Thread {
/**
* 利用继承中的特点 * 将线程名称传递 进行设置
*/
public MyThread(String name) {
super(name);
}
/**
* 重写run方法 * 定义线程要执行的代码
*/
public void run() {
for (int i = 0; i < 20; i++) {
//getName()方法 来自父亲
System.out.println(getName() + i);
}
}
}
测试类:
public class Demo {
public static void main(String[] args) {
System.out.println("这里是main线程");
MyThread mt = new MyThread("小强");
mt.start();//开启了一个新的线程
for (int i = 0; i < 20; i++) {
System.out.println("旺财:"+i);
}
实现Runnable方式(implements Runnable)
定义实现类:
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
定义测试类:
public class Demo {
public static void main(String[] args) {
//创建自定义类对象 线程任务对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t = new Thread(mr, "小强");
t.start();
for (int i = 0; i < 20; i++) {
System.out.println("旺财 " + i);
}
实现的方式
8,1主线程等待
当主线程没有获取到值时,主线程等待子线程完成赋值。、
优点:实现简单,
缺点:
子线程:
public class CycleWait implements Runnable {
private String name;
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
name = "we have date now";
}
}
主线程:
// 主线程
public static void main(String[] args) throws Exception {
CycleWait cw = new CycleWait();
Thread t = new Thread(cw);
t.start();
// 当辅助线程中name没有值时,主线程等待
while (cw.name == null) {
Thread.sleep(100);
}
System.out.println(cw.name);
}
8.2 使用Thread类的join()阻塞当前线程等待子线程处理完毕
替换为:t.join( )等待该线程终止。
// 主线程
public static void main(String[] args) throws Exception {
CycleWait cw = new CycleWait();
Thread t = new Thread(cw);
t.start();
当辅助线程中name没有值时,主线程等待
t.join();
System.out.println(cw.name);
}
8.3 通过Callable接口:通过FutureTask或者线程池实现
子线程:
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.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("wait");
}
System.out.println("task return="+task.get());
}
}
执行结果:
使用线程池方式:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 1、创建线程池
ExecutorService pool = Executors.newCachedThreadPool();
// 2、获取返回的结果
Future<String> result = pool.submit(new MyCallable());
// 3、线程等待
if (!result.isDone()){
System.out.println("wait ..");
}
try {
// 4、获取返回值
System.out.println(result.get());
} catch (Exception e) {
e.printStackTrace();
}finally {
// 5、关闭线程池
pool.shutdown();
}
}
}
线程状态 | 导致状态发生条件 |
---|---|
NEW(新建) | 线程刚被创建,但是并未启动。还没调用start方法。 |
Runnable(可运行) | 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。 |
Blocked(锁阻塞) | 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。 |
Waiting(无限等待) | 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。 |
TimedWaiting(计时等待) | 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep. |
Teminated(被终止) | 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。 |
无限等待(Waiting)
没有设置 Timeout参数的 object.wait( )方法。
没有设置 Timeout参数的 Threadjoin( )方法。
LockSupport.park( )方法。
限期等待(Timed Waiting)
Thread.sleep( )方法。
设置了 Timeout参数的 Object.wait( )方法。
设置了 Timeout参数的 Thread.join( )方法。
LockSupport.parkNanps( )方法。
LockSupport parkUntil( )方法。
基本的差别
最主要的本质区别
public class WaitSleepDemo {
public static void main(String[] args) {
//创建lock锁对象
final Object lock = new Object();
//启动线程A
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread A is waiting to get lock");
synchronized (lock){
try {
System.out.println("thread A get lock");
Thread.sleep(20);
System.out.println("thread A do wait method");
lock.wait(1000);
System.out.println("thread A is done");
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
//线程等待10s让线程A,执行到wait( );
Thread.sleep(10);
//启动线程B
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread B is waiting to get lock");
synchronized (lock){
try {
System.out.println("thread B get lock");
System.out.println("thread B is sleeping 10 ms");
Thread.sleep(10);
System.out.println("thread B is done");
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
}
}
执行结果:
thread A is waiting to get lock
thread A get lock
thread B is waiting to get lock
thread A do wait method
thread B get lock
thread B is sleeping 10 ms
thread B is done
thread A is done
两个概念:
锁池:
假设线程A已经拥有了某个对象(不是类)的锁,而其它线程B、C想要调用这个对象的某个 synchronized方法(或者块),由于B、C线程在进入对象的 synchronized方法(或者块)之前必须先获得该对象锁的拥有权,而恰巧该对象的锁目前正被线程A所占用,此时B、C线程就会被阻塞,进入一个地方去等待锁的释放,这个地方便是该对象的锁池
等待池(Object.wait( )):
假设线程A调用了某个对象的wat()方法,线程A就会释放该对象的锁,同时线程A就进入到了该对象的等待池中,进入到等待池中的线程不会去竞争该对象的锁。
notify和norifyAll的区别?
public static native void yield() 暂停当前正在执行的线程对象,并执行其他线程。
概念
当调用 Thread.yield( )函数时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽略这个暗示。
public class YieldDemo {
public static void main(String[] args) {
Runnable yieldTask = new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + i);
if (i == 5) {
Thread.yield();
}
}
}
};
Thread t1 = new Thread(yieldTask, "A");
Thread t2 = new Thread(yieldTask, "B");
t1.start();
t2.start();
}
}
执行结果:
请求让出CPU执行的,不一定会被采纳,可能会让你继续执行(B1后还是B线程 的B2),也可能让出(B5后换成A线程的A1)。
B1
B2
B3
B4
B5
A1
B6
A2
A3
A4
A5
A6
A7
A8
A9
A10
已经被抛弃的方法
目前使用的方法
调用 interrupt0,通知线程应该中断了
需要被调用的线程配合中断。
代码:
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Runnable interruptTask = new Runnable() {
@Override
public void run() {
int i = 0;
try {
//在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(100); // 休眠100ms
i++;
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") loop " + i);
}
} catch (InterruptedException e) {
//在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") catch InterruptedException.");
}
}
};
// 启动“线程t1”
Thread t1 = new Thread(interruptTask, "t1");
System.out.println(t1.getName() + " (" + t1.getState() + ") is new.");
t1.start();
System.out.println(t1.getName() + " (" + t1.getState() + ") is started.");
// 主线程休眠300ms,然后主线程给t1发“中断”指令。
Thread.sleep(300);
t1.interrupt();
System.out.println(t1.getName() + " (" + t1.getState() + ") is interrupted.");
// 主线程休眠300ms,然后查看t1的状态。
Thread.sleep(300);
System.out.println(t1.getName() + " (" + t1.getState() + ") is interrupted now.");
}
}
执行结果:
t1 (NEW) is new. //线程被新创建。
t1 (RUNNABLE) is started. 线程执行,(调用start( )方法)
t1 (RUNNABLE) loop09 1 //线程正在执行
t1 (RUNNABLE) loop09 2 //线程正在执行
t1 (RUNNABLE) catch InterruptedException. //线程正在阻塞,调用抛出异常
t1 (TIMED_WAITING) is interrupted. //继续执行后面的逻辑
t1 (TERMINATED) is interrupted now. //线程已经终止