进程和线程的关系
进程是所有线程的集合,每一个线程是进程中的一条执行路径。
什么是进程,什么是线程
进程,每个正在系统上运行的程序都是一个进程。
线程,线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行,每个进程包含一到多个线程。
多线程的好处(类比同步跟异步的概念)
☞ 提高执行任务的效率
☞ 线程(任务)之间互相不影响,如果其中一个线程挂掉,另一个照常运行
Java中三种创建线程的方式
1、继承Thread类
☞ 创建继承类InheritThread,重写run()方法
public class InheritThread extends Thread {
@Override
public void run() {
System.out.println("run()方法被执行...");
}
}
☞ 创建主线程类ThreadDemo,在main()方法中调用继承类
public class ThreadDemo {
public static void main(String[] args) {
System.out.println("创建新线程...");
InheritThread inheritThread = new InheritThread();
inheritThread.start(); //启动一个线程是调用start()方法,而不是直接调用run()方法
System.out.println("新线程已启动...");
System.out.println("main()方法启动...");
}
}
结果:
ps:直接调用run()方法来运行相当于还是在主线程中而不是重新启动一个新线程;多线程的执行顺序是交叉执行的,以上的结果虽然看不出来交叉执行的效果,但是当线程执行的次数够多(例如循环)时,就能够体现出交叉执行的效果。
2、实现Runnable接口(推荐)
创建实现Runnable接口的实现类ImplementRunnable
public class ImplementRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++){
System.out.println("run()==>"+i);
}
}
}
主线程
ImplementRunnable implementRunnable = new ImplementRunnable();
System.out.println("创建新线程...");
Thread thread = new Thread(implementRunnable); //传入对象,无法直接调用start()方法
thread.start();
System.out.println("新线程已启动...");
System.out.println("main()方法启动...");
for (int i = 0; i < 100; i++){
System.out.println("main()==>"+i);
}
ps:继承Thread和实现接口Runnable的功能一样,但是推荐使用实现接口的方式,因为接口可以多实现,而继承只能单继承。
3、利用匿名内部类
无需创建其他类,只需要在主线程中创建一个匿名内部类即可
System.out.println("创建新线程...");
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("run()==>" + i);
}
}
}).start();
System.out.println("新线程创建成功...");
for (int i = 0; i < 100; i++){
System.out.println("main()==>"+i);
}
常用的方法
1、sleep()
☞ 让当前线程从运行状态转为休眠状态,如果休眠时间到了,则又恢复为运行状态(利用延时可以清楚的看出交叉执行的效果);
☞ 无法释放锁
@Override
public void run() {
for (int i = 0; i < 10; i++){
try { //在run()方法中不能抛出异常,只能捕获异常
Thread.sleep(1000); //延时1秒
} catch (InterruptedException e) {
}
System.out.println("i="+i);
}
}
2、设置线程的名称
public class TestThread extends Thread {//只有使用继承的方式才能使用getId()方法和getName()方法
@Override
public void run() {
for (int i = 0; i < 10; i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println("线程ID:"+getId()+" 线程名称:"+getName()+" ==>>i="+i);
}
}
}
public static void main(String[] args) {
TestThread thread = new TestThread();
thread.setName("线程1");
thread.start();
TestThread thread2 = new TestThread();
thread2.setName("线程2");
thread2.start();
}
使用实现接口的方式
public class TestThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
Thread thread = Thread.currentThread(); //获取当前线程,才能调用具体的设置方法
System.out.println("线程ID:"+thread.getId()+" 线程名称:"+thread.getName()+" ==>>i="+i);
}
}
}
TestThread2 testThread2 = new TestThread2();
Thread thread = new Thread(testThread2);
thread.start();
效果同上
3、join()方法的使用
☞ 将优先级提高,等到该线程执行完后再执行其他线程
public static void main(String[] args) {
Thread threadJoin = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 60; i++) {
System.out.println("子线程i: " + i);
}
}
});
threadJoin.start();
try {
threadJoin.join(); //提高子线程的优先级
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 30; i++) {
System.out.println("主线程: "+i);
}
System.out.println("主线程执行完毕...");
}
☞ 效果
多线程的运行状态(5种)
新建状态==》就绪状态==》运行状态==》休眠状态==》死亡状态
新建状态:创建,但未调用start()方法
就绪状态:调用了start()方法,等待CPU的调度
运行状态:CPU分配资源执行run()方法后
休眠状态:调用了sleep()或wait()方法,休眠结束后会回到就绪状态,继续等待CPU的调度
死亡状态:run()方法执行完成或手动调用stop()方法[一般不调用stop()方法]后
// 2019 / 04 / 14更新
守护线程
☞ 守护线程跟用户线程的区别在于守护线程会随着主线程的销毁而销毁
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程i: " + i);
}
}
});
t1.setDaemon(true); //设置为守护线程,和主线程一起销毁
t1.start();
for (int j = 0; j < 5; j++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程j: "+j);
}
System.out.println("主线程执行完毕...");
}
☞ 效果