多线程
在编程中,多线程的意思是某个程序同时多个任务,这样的每一个任务则称为一个线程。线程这部分涉及的知识非常多,在实际开发的应用也是非常重要,这里将介绍基本的部分。
概念
线程:操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中实际运作单位。
进程:计算机中已运行程序的实体。进程本身不会运行,是线程的容器。
并行与并发:
- 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
- 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。[1]
实现多线程的几种基本方式
1、继承Thread类
1 | public class Test02 extends Thread{ |
2、实现Runnable接口
1 | public class Test01 implements Runnable{ |
3、使用Callable和Future接口创建线程
1 | public class Test03 implements Callable<Integer>{ |
线程状态
使用getState()
方法可获取当前线程的状态(枚举类型),各种状态如下:
New(新生)
当new一个新的线程时,线程还没开始运行时,状态是new1
2
3
4
5
6public class Test {
public static void main(String[] args) {
Thread thread = new Thread();
System.out.println(thread.getState());
}
}输出
NEW
Runnable(可运行)
线程调用start执行时1
2
3
4
5
6
7
8
9
10
11
12
13public class Test {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
public void run() {
for(int i=0; i<100; i++){
System.out.println("i is "+i);
}
}
});
thread.start();
System.out.println(thread.getState());
}
}输出
RUNNABLE
i is 0
i is 1
...i is 99
Blocked(被阻塞)
当一个线程试图获取一个内部的对象锁(而不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态。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
29public class Test {
final Object lock = new Object();
class Example implements Runnable{
private String name;
public Example(String name) {
this.name = name;
}
public void run() {
//同步代码块
synchronized (lock) {
for(int i=0; i<100; i++){
System.out.println(name+": i is "+i);
}
}
}
}
public static void main(String[] args) {
Example example1 = new Test().new Example("test1");
Example example2 = new Test().new Example("test2");
Thread thread1 = new Thread(example1);
Thread thread2 = new Thread(example2);
thread1.start();
thread2.start();
System.out.println(thread1.getState());
System.out.println(thread2.getState());
}
}输出
RUNNABLE
test1: i is 0
test2: i is 0
test1: i is 1
BLOCKED
test1: i is 2
...Waiting(等待)
等待状态,释放自身的锁进入Waiting状态并加入线程等待队列1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class Test {
public synchronized void testMethod(){
try {
this.wait();
System.out.println("waiting closed.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
public void run() {
new Test().testMethod();
}
});
thread1.start();
Thread.sleep(10);//主线程休眠,转而去执行子进程
System.out.println(thread1.getState());
}
}输出
WAITING
waiting closed并不会输出Timed waiting(计时等待)
在this.wait();
加上等待时间就会进入计时等待状态,例如this.wait(3000);
等待三秒输出内容TIMED_WAITING
waiting closed.
Terminated(被终止)
run方法执行结束线程终止1
2
3
4
5
6
7
8
9
10
11
12public class Test {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
public void run() {
System.out.println("run success");
}
});
thread.start();
Thread.sleep(100);
System.out.println(thread.getState());
}
}
线程管理
sleep方法
static void sleep(long millis)
让当前正在运行的线程休眠一段时间
sleep是一个静态方法,不要用实例化的线程对象调用,其作用的是当前正在运行的线程。Thread.sleep(2000);
表示让当前线程休眠2秒,这里的2秒并不是准确的时间段,因为线程是由系统控制,实际时间可能大于2秒。yield方法
static void yield()
暂停当前正在执行的线程,重新进入就绪状态,这也是和sleep方法的区别的地方。如果有其他的可运行线程具有至少与此线程同样高的优先级,那么这些线程接下来会被调度。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
25public class Test {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
public void run() {
for(int i=0; i<100; i++){
System.out.println("one--"+i);
}
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
thread1.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0; i<100; i++){
System.out.println("two--"+i);
}
}
});
thread2.start();
}
}thread1在thread2中启动,为thread2子线程,调用join,等待thread1执行结束再执行thread2,相当于把两线程合并了。
void join(long millis)
join重载方法带参数,在指定时间段子线程未执行完将重新进入就绪状态,等待cpu调度。notify和notifyAll方法
notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。
notifyAll 会唤醒所有等待(对象的)线程。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
35public class Test {
public synchronized void testMethod(){
try {
System.out.println("thread start.");
this.wait();
System.out.println("waiting closed.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void notifyMethod(){
this.notifyAll();
}
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread thread1 = new Thread(new Runnable() {
public void run() {
test.testMethod();
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
test.notifyMethod();
System.out.println("唤醒线程.....");
}
});
thread1.start();
Thread.sleep(1000);
System.out.println(thread1.getState());
thread2.start();
}
}输出
thread start.
WAITING
唤醒线程.....
waiting closed.
interrupted和isInterrupted
Interrupted方法是一个静态方法,它检测当前的线程是否被中断。而且,调用interrupted方法会清除该线程的中断状态。
另一方面,isInterrupted方法是一个实例方法,可用来检验是否有线程被中断。调用这个方法不会改变中断状态。setPriority和getPriority
void setPriority(int newPriority)
设置线程的优先级。优先级必须在Thread.MIN_PRIORITY 与Thread.MAX_PRIORITY之
间。一般使用Thread.NORM_PRIORITY 优先级。final int getPriority()
获取线程的优先级结束线程
Tread中有stop方法,但改方法已经过时,不推荐使用。要结束线程,可设置标志来实现。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class Test {
class TestTread implements Runnable{
private boolean flag;
private void stopThread() {
this.flag=true;
}
public void run() {
for(int i=0; i<1000 && !flag; i++){
System.out.println("i is "+i);
}
}
}
public static void main(String[] args) throws InterruptedException {
TestTread test = new Test().new TestTread();
Thread thread1 = new Thread(test);
thread1.start();
Thread.sleep(3);//休眠延时
test.stopThread();
}
}输出一段i的值之后当执行stopThread方法线程就结束了。