java 多线程笔记

进程(Processor)和线程(Thread)的区别

进程是操作系统分配资源的最小单位,一个进程可以包含一个或多个线程。
线程是进程的子集,是进程中的子进程,是CPU调度的最小单位。
进程是资源分配的最小单位,线程是CPU调度的最小单位。

创建线程的三种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SearchFile extends Thread{

private File file;
private String content;

public KillThread(File file, String content){
this.file = file;
this.content = content;
}

public void run(){
while(file.isFile()){
file.search(content);
}
}
}
1
2
3
4
5
6
7
8
9
public class RunFile extends Thread{
public static void main(String[] args) {
File file = new File("C:\\test.txt")
String content = "123";
SearchFile sf = new SearchFile(file,content);
// 用对象的start()方法启动线程
sf.start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SearchFile implements Runnable{

private File file;
private String content;

public KillThread(File file, String content){
this.file = file;
this.content = content;
}

public void run(){
while(file.isFile()){
file.search(content);
}
}
}
1
2
3
4
5
6
7
8
9
public class RunFile extends Thread{
public static void main(String[] args) {
File file = new File("C:\\test.txt")
String content = "123";
SearchFile sf = new SearchFile(file,content);
// 新建的线程的start()方法启动线程
new Thread(sf).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
42
43
44
45
46
47
48
49
50
51
52
53
package multiplethread;

import charactor.Hero;

public class TestThread {

public static void main(String[] args) {

Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
gareen.damage = 50;

Hero teemo = new Hero();
teemo.name = "提莫";
teemo.hp = 300;
teemo.damage = 30;

Hero bh = new Hero();
bh.name = "赏金猎人";
bh.hp = 500;
bh.damage = 65;

Hero leesin = new Hero();
leesin.name = "盲僧";
leesin.hp = 455;
leesin.damage = 80;

//匿名类
Thread t1= new Thread(){
public void run(){
//匿名类中用到外部的局部变量teemo,必须把teemo声明为final
//但是在JDK7以后,就不是必须加final的了
while(!teemo.isDead()){
gareen.attackHero(teemo);
}
}
};

t1.start();

Thread t2= new Thread(){
public void run(){
while(!leesin.isDead()){
bh.attackHero(leesin);
}
}
};
t2.start();

}

}

start()和run()

直接调用run()方法,相当于调用了一个普通的Java方法,当前线程并没有任何改变,也不会启动新线程。上述代码实际上是在main()方法内部又调用了run()方法,打印hello语句是在main线程中执行的,没有任何新线程被创建

必须调用Thread实例的start()方法才能启动新线程,如果我们查看Thread类的源代码,会看到start()方法内部调用了一个private native void start0()方法,native修饰符表示这个方法是由JVM虚拟机内部的C代码实现的,不是由Java代码实现的。

线程的优先级

可以对线程设定优先级,设定优先级的方法是:

Thread.setPriority(int n) // 1~10, 默认值5

JVM自动把1(低)~10(高)的优先级映射到操作系统实际优先级上(不同操作系统有不同的优先级数量)。优先级高的线程被操作系统调度的优先级较高,操作系统对高优先级线程可能调度更频繁,但我们决不能通过设置优先级来确保高优先级的线程一定会先执行。

join()方法

当main线程对线程对象t调用join()方法时,主线程将等待变量t表示的线程运行结束,即join就是指等待该线程结束,然后才继续往下执行自身线程。所以,上述代码打印顺序可以肯定是main线程先打印start,t线程再打印hello,main线程最后再打印end。

start–>hello–>end

1
2
3
4
5
6
7
8
9
10
11
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");
}
}

守护线程(Daemon Thread)

守护线程是指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。

因此,JVM退出时,不必关心守护线程是否已结束。

创建守护线程

在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程:

1
2
3
Thread t = new MyThread();
t.setDaemon(true);
t.start();
注意事项

守护线程的优先级永远是5,不能通过setPriority()方法来改变。

守护线程不能启动新线程,否则会抛出IllegalThreadStateException异常。

守护线程不能访问非守护线程的成员变量,因为当守护线程结束后,JVM退出,非守护线程的成员变量也就不存在了。

守护线程不能抛出UncaughtException异常,因为JVM退出时,会先销毁守护线程,如果守护线程抛出异常,将导致JVM退出。

守护线程不能调用interrupt()方法,因为JVM退出时,会先销毁守护线程,如果守护线程调用interrupt()方法,将导致JVM退出。

守护线程不能调用join()方法,因为JVM退出时,会先销毁守护线程,如果守护线程调用join()方法,将导致JVM退出。

守护线程不能调用setUncaughtExceptionHandler()方法,因为JVM退出时,会先销毁守护线程,如果守护线程调用setUncaughtExceptionHandler()方法,将导致JVM退出。

守护线程不能调用setName()方法,因为JVM退出时,会先销毁守护线程,如果守护线程调用setName()方法,将导致JVM退出。

守护线程不能调用setPriority()方法,因为JVM退出时,会先销毁守护线程,如果守护线程调用setPriority()方法,将导致JVM退出。

守护线程不能调用setDaemon()方法,因为JVM退出时,会先销毁守护线程,如果守护线程调用setDaemon()方法,将导致JVM退出。

守护线程不能调用setContextClassLoader()方法,因为JVM退出时,会先销毁守护线程,如果守护线程调用setContextClassLoader()方法,将导致JVM退出。

为什么使用synchronized需要创建一个Object对象作为锁?

synchronized修饰的方法或代码块,必须指定一个锁对象,这个锁对象可以是任意对象,只要确保这个对象是唯一的

我的理解是:这是一个yellow 遥控器,被访问的对象就是green 电视机,只有拿到yellow 遥控器才能控制green 电视机,所以遥控器就是锁对象