多线程及并发的基础重新学习与记录

什么是多线程

多线程的创建及启动

创建,启动新线程有两种方法:

  • 定义Thread的子类并重写其run方法;创建Thread实例创建新线程;调用start方法启动新线程:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class T2 extends Thread {

    public static void main(String[] args) {
    Thread t = new T2();
    t.start();
    }

    @Override
    public void run() {
    for (int i = 0; i < 100; i++) {
    System.out.println("Runner1" + i);
    }
    }
    }

  • 定义线程类实现Runnable接口; 创建Thread实例创建新线程;调用start方法启动新线程(推荐使用这一种,多用接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class T {

public static void main(String[] args) {
Runnable r1 = new Runner1();
Thread t1 = new Thread(r1);
t1.start();

for (int i = 0; i < 100; i++) {
System.out.println("Main Thread" + i);
}
}


}

class Runner1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("Runner1" + i);
}
}
}

在java8中也可以利用Lambda表达式写成如下格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class T {

public static void main(String[] args) {
//Runnable 是函数接口 可以使用Lambda表达式书写
Thread t = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("Runner1" + i);
}
});
t.start();

for (int i = 0; i < 100; i++) {
System.out.println("Main Thread" + i);
}

}
}

线程状态转换

TIM截图20180501214047.png-213.8kB

线程控制基本方法

sleep()

静态方法,时当前线程进入阻塞状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}

if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}

sleep(millis);
}

&ensp;&ensp;这是Thread内的老的sleep方式,但是用这个方法来使线程进入阻塞状态不是特别好。例如:Thread.sleep(2400000)这样的方法调用无法一眼得知阻塞的时间。即便写成Thread.sleep(4*60*1000)也不是一目了然。因此在java5之后新增了TimeUnit枚举类来代替sleep()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class T3 {
public static void main(String[] args) {
try {
// Thread.sleep(10000);
TimeUnit.MILLISECONDS.sleep(10);// sleep 10 毫秒
TimeUnit.SECONDS.sleep(10);// sleep 10 秒
TimeUnit.MINUTES.sleep(10);// sleep 10 分钟
TimeUnit.HOURS.sleep(10);// sleep 10 小时
TimeUnit.DAYS.sleep(10);// sleep 10 天
} catch (InterruptedException e) {
}
}

}

interrupt()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class T3 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true) {
System.out.println("===" + new Date() + "===");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
}
});

t.start();

try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}

t.interrupt();

}
}

优先级

Thread.currentThread().setPriority()程序代码中可以对各线程设置优先级,使cpu执行高优先级线程的频率更高。
不过由于不同才做系统中线程调度并不相同,因此要尽量少的使用此方法,最多只使用MAX_PRIOPRITYNORM_PRIOPRITYMIN_PRIOPRITY三个优先级

“在绝大多数时间里,所有线程都应该以默认的优先级运行。试图操纵线程优先级通常是一种错误。” 《Thinking in Java》

后台线程

&ensp;&ensp;后台线程是指程序运行的时候在后台提供一种通用服务的线程。当所有非后台线程结束时,程序结束,同时会杀死所有后台线程。
后台线程创建实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class T3 {

public static void main(String[] args) {
Thread t = new Thread((() -> {
while (true) {
System.out.println( new Date() + "===");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}), "Thread1");
t.setDaemon(true);
t.s8tart();
}

}

必须在启动线程之前调用setDeamom方法, 才能把它设置为后台线程