文章字数:1413,阅读全文大约需要5分钟
基本概念
- 进程:进程拥有独立的代码和数据空间,是资源分配的最小单位。一个进程可以包含一个或多个线程。
- 线程:同一类的线程共享代码和数据空间,每个线程都拥有独立的运行栈和程序计数器。线程是cpu调度的最小单位。
- 进程/线程 的五个状态:创建、就绪、运行、阻塞、终止
- 多进程代表操作系统可运行多程序,线程代表程序里运行多个顺序流
创建java线程
java创建线程有三种方法
- 基础Thread类
- 实现Runable接口
- 实现Callable接口,配合Future、线程池
继承Thread
类
1 | class threadLearn extends Thread{ |
实现java.lang.Runnable
接口
1 | class ThreadLearn implements Runnable{ |
start()
方法使线程变成可运行状态Runnable
,操作系统决定何时调用运行。start()
方法重复调用会抛出java.lang.IllegalThreadStateException
异常run()
方法是多线程程序的一个约定,所有的多线程代码都要写在里面。
Thread
和Runnable
比较
Thread
本质上是实现了Runnable
接口。Thread
类实现了Runnable
并在其之上进行了拓展。
线程状态
线程状态 | 状态分类 | 描述 |
---|---|---|
新建状态New |
- | 新创建了一个线程对象 |
就绪状态Runnable |
- | 其它线程调用了该线程的start() 方法,线程变为可运行 |
运行状态Running |
- | 就绪状态的线程被系统调用。 |
阻塞状态Blocked |
- | 分为三种情况 |
阻塞状态 | 等待阻塞 | 运行的线程执行wait() 方法 |
阻塞状态 | 同步阻塞 | 获取同步锁时锁被其它线程占用,jvm会把该线程放入锁池之中 |
阻塞状态 | 其它阻塞 | 线程运行sleep() 或join() 的线程结束或发出I/O请求。sleep 不会释放锁 |
死亡状态 | - | 线程执行完毕或异常退出 |
线程调度
- 线程优先级
- Thread的
setPriortity()
和getPriortity()
管理优先级 - 优先级取值1~10整数,推荐使用常量,这三个级别的可移植性好。
1
2
3static int MAX_PRIORITY=10;
static int NORM_PRIORITY=5;//默认
static int MIN_PRIORITY=1;
线程睡眠
Thread.sleep(long millis)
:设定线程阻塞时间,阻塞结束后进入就绪状态。线程等待
Object
类中的wait()
方法,导致当前线程等待,直到其它线程调用此对象的notify()
方法或者notifyAll()
唤醒,等价于wait(0)
线程让步
Thread.yield()
暂停当前正在执行的线程对象,把执行的机会让给优先级相同或更高的线程。线程加入
join()
当前线程进入阻塞态,调用其它线程,该线程运行完毕后当前线程再进入就绪态。线程唤醒
Object
类的notify()
方法,唤醒对象监听器上一个线程,如果有多个线程在此对象上等待,则唤醒随机一个。notifyAll()
唤醒所有该对象上等待的线程。wait()
和sleep()
都可以通过interrupt()
方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException
。
sleep
方法不会释放锁,wait
会
wait
,notify
和notifyAll
只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
常用方法
sleep()
: 强迫一个线程睡眠N毫秒。isAlive()
: 判断一个线程是否存活。join()
: 等待线程终止。activeCount()
: 程序中活跃的线程数。enumerate()
: 枚举程序中的线程。currentThread()
: 得到当前线程。isDaemon()
: 一个线程是否为守护线程。setDaemon()
: 设置一个线程为守护线程。(用户线程和守护线程的区别在于没有用户线程后守护线程终止)setName()
: 为线程设置一个名称。wait()
: 强迫一个线程等待。notify()
: 通知一个线程继续运行。setPriority()
: 设置一个线程的优先级。
线程同步
synchronized
[ˈsɪŋkrənaɪzd]是系统级的锁,一旦锁死除了线程自行释放没有其它方法。juc的lock锁是编码级别的,可以代码解锁。juc(java.util.concurrent
)下次讨论
synchronized
在对象里:标记于方法或是代码块都是对对象加锁。只要对象中出发了锁,整个对象都无法进入。synchronized
标记于静态方法,则是对于类加锁,和对象锁不冲突
线程数据传递
同步情况下使用参数传入,return返回的形式,多线程下运行和结束是不可预料的,所以无法和同步一样传参。
使用构造方法传参
1
2//线程使用构造函数就收这个参数
Thread thread = new MyThread1("hello world");set方法
线程里先设置set方法接受参数(不用多说了吧)
然后start()之前设置参数1
2
3
4MyThread2 myThread = new MyThread2();
myThread.setName("hello world");
Thread thread = new Thread(myThread);
thread.start();回调函数
将对象传入线程,线程在某一时间调用对象的函数。主线程通过传入的对象获取线程操作后的值。(还有静态类)
声明lambda函数的接口
1
2
3public interface ICallback {
public void callback(Map<String, Object> params);
}线程调用接口返回数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public static void doStm(final ICallback callback) {
// 初始化一个线程
Thread t = new Thread() {
public void run() {
// 这里是业务逻辑处理
System.out.println("子线任务执行:"+Thread.currentThread().getId());
// 为了能看出效果 ,让当前线程阻塞5秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 处理完业务逻辑,
Map<String, Object> params = new HashMap<String, Object>();
params.put("a1", "这是我返回的参数字符串...");
callback.callback(params);
};
};
es.execute(t);
//一定要调用这个方法,不然executorService.isTerminated()永远不为true
es.shutdown();
}1
2
3doStm((params)->{
System.out.println("单个线程也已经处理完毕了,返回参数a1=" + params.get("a1"));
});