线程是什么?
- 进程: 程序运行时一块独立的内存空间
- 线程: 内存中最小的执行单元
ps:工作中基础的用不到,用到的是并发的工具类,线程池
为什么要多进程
进程之间调度起来,上下文切换,保留程序执行信息等,比较消耗资源,无法为多核CPU提供很好的支持
因此有了多线程,线程为CPU执行的单元,在切换时成本大大降低
注: ‘’线程‘’,‘’进程‘’是计算机本身的概念。不是Java语言所特有的能力,其他语言也一样具有此能力。
ps:面试:进程和线程的关系
tudo
线程在Java中长什么样?
- Java是面向对象编程语言,所以Java将如何事物都抽象出了对象,线程也一样。
- 在Java中线程类=Thread
新建个运行的线程
- Thread thread = new Thread(); //新建
- thread.start(); //启动
线程的生命周期
面试可能画这个图,画完后,状态如何切换说清楚。
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() ->{
for (int i = 0; i <100000 ; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.setName("kim");
//调了start之后,线程t1 进入就绪状态
t1.start();
//当cpu 切换到次线程时,才会进入到运行状态
Thread.sleep(1000*60*5);
}
}
执行jsp命令
jstack -l 26391
可看到gc,垃圾回收线程
Demo1定义的线程名称:kim,可以看到,#11就是
localhost:~ cuihailong$ jstack -l 26457
2020-07-04 17:24:35
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode):
"Attach Listener" #12 daemon prio=9 os_prio=31 tid=0x00007ff5c08fe800 nid=0x5703 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"kim" #11 prio=5 os_prio=31 tid=0x00007ff5c2054800 nid=0xa903 waiting on condition [0x000070000d299000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at course.basic.thread.Demo1.lambda$main$0(Demo1.java:12)
at course.basic.thread.Demo1$$Lambda$1/883049899.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007ff5c1800000 nid=0x3a03 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007ff5c1000800 nid=0x3803 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007ff5bf03d000 nid=0x3d03 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007ff5bf03c000 nid=0x3f03 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007ff5c201c800 nid=0x4103 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007ff5be024000 nid=0x3703 runnable [0x000070000cb84000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x000000079570dc68> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x000000079570dc68> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:61)
Locked ownable synchronizers:
- None
"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007ff5be021800 nid=0x3503 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007ff5be808800 nid=0x4803 in Object.wait() [0x000070000c97e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000795588ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x0000000795588ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
Locked ownable synchronizers:
- None
"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007ff5c181a000 nid=0x4a03 in Object.wait() [0x000070000c87b000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000795586bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x0000000795586bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
Locked ownable synchronizers:
- None
"main" #1 prio=5 os_prio=31 tid=0x00007ff5c1801800 nid=0x1903 waiting on condition [0x000070000be5d000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at course.basic.thread.Demo1.main(Demo1.java:28)
Locked ownable synchronizers:
- None
"VM Thread" os_prio=31 tid=0x00007ff5be003800 nid=0x2e03 runnable
"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007ff5c0807000 nid=0x1f07 runnable
"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007ff5c2000000 nid=0x2a03 runnable
"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007ff5c180a800 nid=0x5303 runnable
"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007ff5c180b000 nid=0x5103 runnable
"GC task thread#4 (ParallelGC)" os_prio=31 tid=0x00007ff5be001800 nid=0x4f03 runnable
"GC task thread#5 (ParallelGC)" os_prio=31 tid=0x00007ff5c180b800 nid=0x4d03 runnable
"GC task thread#6 (ParallelGC)" os_prio=31 tid=0x00007ff5be002800 nid=0x2b03 runnable
"GC task thread#7 (ParallelGC)" os_prio=31 tid=0x00007ff5be003000 nid=0x2c03 runnable
"VM Periodic Task Thread" os_prio=31 tid=0x00007ff5bf03d800 nid=0x5503 waiting on condition
JNI global references: 319
localhost:~ cuihailong$
Runnable接口
Thread)(线程)常用方法
- start()
- 线程调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以脱离创建它的线程独立开始自己的生命周期了
- run()
- Thread类的run()方法与Runnable接口中的run()方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户程序不得引用的方法
- sleep(int millsecond)
- 优先级高的线程可以在它的run()方法中调用sleep方法来使自己放弃CPU资源,休眠一段时间
- isAlive()
- 线程处于“新建”状态时,线程调用isAlive()方法返回false。在线程的run()方法结束之前,即没有进入死亡状态之前,线程调用isAlive()方法返回true
- currentThread()
- 该方法是Thread类中的类方法,可以用类名调用,该方法返回当前正在使用CPU资源的线程
- interrupt()
- 一个占有CPU资源的线程可以让休眠的线程调用interrupt()方法“吵醒”自己,即导致休眠的线程发生InterruptedException异常,从而结束休眠,重新排队等待CPU资源。
- join()
- 作用是等待线程对象销毁
- 主线程创建并启动了线程,如果子线程中要进行大量耗时运算,主线程往往将早于子线程结束之前结束。这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。方法join()的作用是等待线程对象销毁
- yield()
- 暂停当前正在执行的线程对象,并执行其他线程
- setDaemon(boolean on) —守护线程
- 设置为后台线程
(启动线程前设置thread.setDaemon(True) 即 设置该线程为守护线程,
表示该线程是不重要的,进程退出时不需要等待这个线程执行完成。
这样做的意义在于:避免子线程无限死循环,导致退不出程序,也就是避免传说中的孤儿进程。)
- 设置为后台线程
join例子
public static void main(String[] args) throws InterruptedException {
// Main Thread
System.out.println("main start:" + LocalDateTime.now());
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000 * 10);
System.out.println("t1 finished:" + LocalDateTime.now());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.setDaemon(true);
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000 * 20);
System.out.println("t2 finished:" + LocalDateTime.now());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t2.setDaemon(true);
t2.start();
t1.join();
t2.join();
System.out.println("main end:" + LocalDateTime.now());
}
结果
main start:2020-07-04T19:18:32.082
t1 finished:2020-07-04T19:18:42.088
t2 finished:2020-07-04T19:18:52.088
main end:2020-07-04T19:18:52.089
Process finished with exit code 0
Java内存模型
- 线程间共享了数据之后会发生什么
线程安全问题
出现原因:
由于内存数据的模型问题,导致多线程之间共享数据时会出现差异
- 示例代码
Integer data = 0;
Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Demo7 demo7 = new Demo7();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
demo7.add();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
demo7.sub();
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("demo7.data = " + demo7.data);
}
// 此时的锁是 new Demo7(); 这个 对象本身
// public synchronized void add() {
// this.data++;
//
// /**
// * 等同于 如下写法
// * synchronized (this) {
// * this.data++;
// * }
// */
// }
//
// public synchronized void sub() {
// this.data--;
// }
public void add() {
synchronized (lock) {
this.data++;
}
}
public void sub() {
synchronized (lock) {
this.data--;
}
}
结果
demo7.data = 0