12.线程基础

线程基础

1.线程相关概念:
程序(program):代码
进程:是指运行中的程序,进程是程序的一次执行过程,或是正在运行的一个程序,是动态过程,有自身的产生、存在和消亡的过程,进程在运行时会占用内存空间
线程:线程由进程创建的,是进程的一个实体,一个进程可以有多个线程

1.创建线程的两种方式

1.继承Thread类,重写run方法

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
//1.开启线程,每隔1秒在控制台输出"喵喵,我是小猫咪"
public class work1 {
public static void main(String[]args) throws InterruptedException{
//创建cat对象当线程使用
cat c1 = new cat();
c1.start();
//当main线程启动了一个子线程 Thread-0,主线程不会阻塞,会继续执行,这时,主线程和子线程是交替执行……
System.out.println("主线程继续执行"+Thread.currentThread().getName());
for(int i = 0;i<60;i++) {
System.out.println("主线程 i=" + i);
Thread.sleep(1000);
}
}
}
class cat extends Thread{
public void run() { //重写run方法,写上自己的业务逻辑
int times = 0;
while(true) {
//当时出3次时结束
if(times == 3) {
break;
}
System.out.println("喵喵,我是小猫咪");
//让该线程休眠一秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
times++;

}
}
}

2.实现Runnable接口,重写run方法

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
74
75
76
/*java是单继承的,在某些情况下一个类可能已经继承了某个父类,再用Thread类方法来创建线程显然不可能了
java还可以通过实现Runnable接口来创建线程*/
//每隔一秒再控制台输出"hi",每当输出10次后,自动退出,实现Runnable接口
public class work2 {
public static void main(String[]args) {
dog d1 = new dog();
//创建了Thread对象,把dog对象(实现了Runnable),放入Thread
Thread t1 = new Thread(d1);
t1.start();
}
}
class dog implements Runnable{
int count = 0;
public void run() {
while(true)
{
System.out.println("小狗叫"+(++count)+ Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(count == 10) {
break;
}
}
}
}
//2.创建两个线程
public class work3 {
public static void main(String []args) {
t3 t = new t3();
t4 t2 = new t4();
Thread th1 = new Thread(t);
Thread th2 = new Thread(t2);
th1.start();
th2.start();
}
}
class t3 implements Runnable{
int n = 0;
public void run() {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
n++;
System.out.println("hei"+n);
if(n ==10) {
break;
}
}
}
}
class t4 implements Runnable{
int n = 0;
public void run() {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
n++;
System.out.println("hello"+n);
if(n == 10) {
break;
}
}
}
}

3.实现Runnable接口方式更加适合多个线程共享一个资源的情况,也避免了单继承的限制,建议使用Runnable
4.线程终止

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
//1.当线程完成任务后,会自动退出
//2.还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式
public class work4 {
public static void main(String[]args) throws InterruptedException {
thread th = new thread();
Thread t1 = new Thread(th);
t1.start();
System.out.println("main程正在运行");
Thread.sleep(10*1000); //让线程休眠50ms
th.setLoop(false);
}
}
class thread implements Runnable{
boolean loop = true;
int count = 0;
public void run() {
while(loop) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("运行中"+(++count));
}
}
//提供的set方法,方便更新变量loop
public void setLoop(boolean loop) {
this.loop=loop;
}
}

2.线程插队

t1.join() //等待某线程结束,再恢复当前线程的运行
t1.yield() //让出CPU资源,当前线程进入就绪状态
注意: yield()是让出资源,但并不放弃。它会进入就绪状态,也就是说:它还会与其他线程一起抢占资源,所以yield()的线程,仍然有可能再次抢占资源。在加上线程运行的不确定性,所以会导致上面的结论并不是绝对的,只是出现的概率要高一些。

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
public class work5 {
public static void main(String[]args) throws InterruptedException {
T t = new T();
Thread t1 = new Thread(t);
for(int i = 1;i<=10;i++) {
System.out.println("hi"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(i==5) {
t1.start();
t1.join(); //等待某线程结束,再恢复当前线程的运行
}
}
}
}
class T implements Runnable{
public void run() {
for(int i = 1;i<=10;i++) {
System.out.println("hello"+ i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

3.线程优先级

1.Java线程有优先级,优先级高的线程会获得较多的CPU运行机会。
2.Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
Java线程的优先级用整数表示,取值范围是1~10; 10最高级。
3.每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY(5)

4.守护线程

守护线程:一般是为工作线程服务的,当所有用户线程结束,守护线程自动结束,常见的守护进程是垃圾回收机制
如果我们希望当前main线程结束后,子线程自动结束,我们只需要将子线程设置成守护线程即可:xxx.setDaemon(true);该语句要放在xxx.start();语句前

5.线程的生命周期

1.NEW //尚未启动的线程处于此状态
2.RUNNABLE //在java虚拟机中执行的线程处于此状态
3.BLOCKED //被阻塞等待监视器锁定的线程处于此状态
4.WAITING //正在等待另一个线程执行特定动作的线程处于此状态
5.TIMED_WAITING //正待等待另一个线程执行达到指定等待时间的线程处于此状态
6.TERMINATED //已退出的线程处于此状态

6.线程同步

1.在多线程编程,一些敏感数据不允许被多个线程访问,此时就使用同步访问技术,保证数据在任何时刻最多一个线程访问
2.可以理解为当一个线程在对内存操作时,不允许其他线程操作内存

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
//1.同步代码块
synchronized(对象){ //得到对象的锁,才能操作同步代码
//需要被同步的代码
}
//2.方法声明
public synchronized void m(String name){
//需要被同步的代码
}
//案例:解决售票问题
public class work6 {
public static void main(String[]args) {
SellTicket03 s03 = new SellTicket03();
Thread t1 = new Thread(s03);
Thread t2 = new Thread(s03);
Thread t3 = new Thread(s03);
t1.start();
t2.start();
t3.start();
}
}
class SellTicket03 implements Runnable{
private int ticketNum=100;
private boolean loop = true; //控制run方法变量
public synchronized void sell() { //同步方法,在同一时刻,只能有一个线程来执行run方法
if(ticketNum <=0) {
System.out.println("售票结束");
loop = false;
return;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票"+ "剩余票数"+(--ticketNum));
}
public void run() {
while(loop) {
sell();
}
}
}

7.线程锁

1.线程同步会导致会出现线程锁导致程序卡死在某一个地方无法继续执行
下面操作会释放锁
1.当前线程的同步方法、同步代码块执行结束
2.当前线程在同步代码块,同步方法中遇到break、return
3.当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致一场结束
4.当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
下面操作不会释放锁
1.线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁
2.线程执行同步代码块时,其他线程调用了该线程的suspend()方法将线程挂起,该线程不会释放锁,避免使用suspen()和resume()来控制线程


12.线程基础
http://example.com/2023/03/14/java/12.线程基础/
作者
haozi0o0
发布于
2023年3月14日
许可协议