廖雪峰java 进程和线程
多线程基础
1.进程包含线程,且至少包含一个线程
2.可用多进程、多线程、多进程+多线程3钟方式实现多任务
3.一个应用程序可以包含多个进程和多个线程
4.进程的优点:稳定性好 一个进程崩溃不会影响其它进程 缺点:创建一个进程比创建一个线程开销大 进程间通信比线程间通信时间久
线程缺点:一个线程崩溃会影响其它所有线程,进而整个进程
5.单核、多核都可以通过轮流执行任务实现多任务同时执行
6.一个java程序实际上就是一个jvm进程,由一个主线程来执行main()方法,main()方法内部又可以启动多个其它的线程
7.对于大多数Java程序来说,我们说多任务,实际上是说如何使用多线程实现多任务、
8.多线程和单线程相比,需要共享和同步数据。因此,多线程编程的复杂度高,调试更困难
9.操作系统调度的最小任务单位其实不是进程,而是线程。
10.如何调度线程完全由操作系统决定,程序自己不能决定什么时候执行,以及执行多长时间。
创建新线程
自定义Thread类
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 26 27
| public class Main{
public static void main(String[] args){
Thread t = new MyThread();
t.start();
}
}
class MyThread extends Thread{
@Override
public void run(){
System.out.println("This is a new Thread!");
}
}
|
传入Runnable实例
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 26 27
| public class Main{
public static void main(String[] args){
Thread t = new Thread(new MyRunnable());
t.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("This is a new Thread!");
}
}
|
使用lambda语法精简
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Main{
public static void main(String[] args){
Thread t = new Thread(()->{"This is a new Thread!"};);
t.start();
}
}
|
使用匿名类简化写法
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class Main {
public static void main(String[] args) {
System.out.println("main Thread start!");
Thread t1 = new Thread(){
public void run(){
System.out.println("t1 Thread start!");
try{
Thread.sleep(20);
}catch(InterruptedException e){}
System.out.println("t1 Thread end!");
}
}
t1.start();
try{
Thread.sleep(20);
}catch(InterruptedException e){}
System.out.println("main Thread end!");
}
}
|
1 2 3
| { ... }:表示定义了一个Thread类的 匿名子类,并在其中重写了run()方法。
|
设置线程优先级
1 2 3 4 5 6 7
| Thread.setPriority(int n)
操作系统对高优先级线程可能调度更频繁,但我们决不能通过设置优先级来确保高优先级的线程一定会先执行。
|
注意
直接调用线程实例的run方法不会启动线程,相当于调用实例方法
一个线程对象只能调用一次start()方法
线程状态
1 2 3 4 5 6 7 8 9 10 11 12 13
| New:新创建的线程,尚未执行
Runnabble:运行中的线程,正在执行run()方法的Java代码
Blocked:运行中的线程,因为某些操作被阻塞而挂起
Waiting:运行中的线程,因为某些操作在等待中
Timed Waiting:运行中的线程,因为执行sleep()方法正在计时等待
Terminated:线程已终止,因为run()方法执行完毕
|
1 2 3 4 5 6 7 8 9 10 11
| 线程终止的原因:
线程正常终止:run()方法执行到return语句返回;
线程意外终止:run()方法因为未捕获的异常导致线程终止;
对某个线程的Thread实例调用stop()方法强制终止(强烈不推荐使用)
|
等待 join()
一个线程还可以等待另一个线程直到其运行结束
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
|
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
System.out.println("hello");
});
System.out.println("start");
t.start();
t.join();
System.out.println("end");
}
}
|
1 2 3
| join(long)的重载方法也可以指定一个等待时间,超过等待时间后就不再继续等待
|
中断线程
intterupt()
中断一个线程非常简单,只需要在其他线程中对目标线程调用interrupt()方法,目标线程需要反复检测自身状态是否是interrupted状态,如果是,就立刻结束运行
如果线程处于等待状态,例如,t.join()会让线程进入等待状态,如下例对t线程调用intterupted,join()方法会立刻抛出InterruptedException,因此,目标线程只要捕获到join()方法抛出的InterruptedException,就说明有其他线程对其调用了interrupt()方法
t结束之前如果不对hello调用intterupted,hello进程会继续运行
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| public class Main {
public static void main(String[] args) throws InterruptedException {
System.out.println("main thread start!");
Thread t = new myThread();
t.start();
Thread.sleep(10000);
t.interrupt();
System.out.println("main thread end!");
}
}
class myThread() extends Thread{
@Override
public void run(){
Thread hello = new helloThread();
hello.start();
try{
hello.join();
}catch(interruptedException){
System.out.println("myThread intterupted!");
}
hello.interrupt();
}
}
class helloThread() extends Thread{
@Override
public void run(){
int n = 0;
while(!isInterrupted){
n++;
System.out.println("hello"+n);
}
System.out.println("hello"+n+"end!");
}
}
|
设置标志位
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 26 27 28 29 30 31 32 33 34 35
| public class Main {
public static void main(String[] args) throws InterruptedException {
System.out.println("main thread start!");
Thread t = new myThread();
t.start();
t.running=false;
}
}
class myThread() extends Thread{
public vlatile boolean running = true;
@Override
public void run(){
while(running){
}
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| 线程间共享变量需要使用volatile关键字标记,确保每个线程都能读取到更新后的变量值。线程间共享变量每个线程使用时都是使用的副本。
因此,volatile关键字的目的是告诉虚拟机:
• 每次访问变量时,总是获取主内存的最新值;
• 每次修改变量后,立刻回写到主内存。
volatile关键字解决的是可见性问题:当一个线程修改了某个共享变量的值,其他线程能够立刻看到修改后的值。
|
public class Counter{
public static void test(int i){
syncronized(Counter.class){
count+=i;
}
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
~~~java
public class Counter{
public syncronized static void test(int i){
count+=i;
}
}
|
while(true){
try{
String s = q.getTask();
System.out.println("execute task: " + s);
}catch(InterruptedException e){
return;
}
}
}
};
execThread.start();
ts.add(execThread);
Thread.sleep(100);
for(var execThread:ts){
t.interrupt();
}
}
}
}
class taskQueue{
Queue queue = new LinkedList<>();
public syncronized void addTask(String s){
this.queue.add(s);
this.notifiAll();
}
public syncronized String getTask() throws InterruptedException {
while(queue.isEmpty()){
this.wait();
}
return queue.remove();
}
}