进程和线程:
进程是计算机系统资源分配的最小单位,一个进程可以有一个或者多个线程。
线程是计算机运行的最小单位,一个线程只属于一个进程。
一些相关的概念:
单线程:同一个时刻,只允许执行一个线程。
多线程:同一个时刻,可以执行多个线程。
并发和并行:![](https://i-blog.csdnimg.cn/blog_migrate/a322178f07495c82f23472f79acb7e03.png)
创建线程的方法:
Java 提供了三种创建线程的方法:
- 通过实现 Runnable 接口;
- 通过继承 Thread 类本身;
- 通过 Callable 和 Future 创建线程。
创建线程的例子:
-
使用继承Thread来创建线程:
首先是run()方法里面创建一个进程,然后main方法中开了一个主线程,主线程接着开了一个子线程。主线程与子线程的执行是互不影响的。只有所有的线程都结束了进程才结束。
public class test_thread extends Thread {
//主线程:main主线程
public static void main(String[] args) throws InterruptedException {
Cat cat = new Cat();
cat.start();//主线程中又开启了一个子线程
//主线程开启子线程后,不会阻塞:主线程和子线程会交替执行
System.out.println("主线程的名字:"+Thread.currentThread().getName());
for (int i=0;i<10;i++){
System.out.println("主线程执行 i=" + i);
Thread.sleep(1000);
}
}
}
//业务需求:
//1. 当Cat类继承了 Thread 类, 该类就可以当做线程使用
//2. 我们会重写 run 方法, 写上自己的业务代码
//3. run Thread 类 实现了 Runnable 接口的 run 方法
class Cat extends Thread{
//创建一个线程,Cat类继承了Thread
int times=0;
//创建了一个进程:
@Override
public void run() {
//重写run方法
while (true){
System.out.println("喵喵叫。。。。"+(++times) +" "+"子线程名:"+Thread.currentThread().getName());
//休眠1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果等于8次,退出循环:
if (times == 8){
break;
}
}
}
}
为什么开启子线程需要用start(),而不直接调用run();因为如果直接调用run()方法,此时run()方法就是一个普通的方法。此时的线程就main线程,这时主线程不会开启子线程,只会顺序执行,也就变成了单线程了。
public class test_thread02 {
public static void main(String[] args) throws InterruptedException {
Dag dag = new Dag();
dag.run();//这时是执行了一个普通的方法,不会开启一个子线程;这时执行的线程是主线程;
//此时就变成了单线程了,就是main线程;
System.out.println("当前的主线程:"+Thread.currentThread().getName());
for (int i=0;i<9;i++){
System.out.println("输出i ="+ i );
Thread.sleep(1000);
}
}
}
class Dag extends Thread{
//创建一个线程,Cat类继承了Thread
int times=0;
//创建了一个进程:
@Override
public void run() {
//重写run方法
while (true){
System.out.println("喵喵叫。。。。"+(++times) +" "+"子线程名:"+Thread.currentThread().getName());
//休眠1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果等于8次,退出循环:
if (times == 8){
break;
}
}
}
}
喵喵叫。。。。1 子线程名:main
喵喵叫。。。。2 子线程名:main
喵喵叫。。。。3 子线程名:main
喵喵叫。。。。4 子线程名:main
喵喵叫。。。。5 子线程名:main
喵喵叫。。。。6 子线程名:main
喵喵叫。。。。7 子线程名:main
喵喵叫。。。。8 子线程名:main
当前的主线程:main
输出i =0
输出i =1
输出i =2
输出i =3
输出i =4
输出i =5
输出i =6
输出i =7
输出i =8
- 实现runnable接口来创建线程:
public class test_runnable {
public static void main(String[] args) {
//创建子线程:
Tiger tiger = new Tiger();
//因为runnable接口没有start方法:所以需要动态代理的方式:
Thread thread = new Thread(tiger);
thread.start();//开启子线程:
System.out.println("当前主线程的名字是:"+Thread.currentThread().getName());
}
}
class Tiger implements Runnable{
//实现了Runnable接口:
int times=0;
@Override
public void run() {
while (true){
System.out.println("老虎饿了"+(++times) + " "+"当前的线程名是:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (times == 10){
break;
}
}
}
}
多线程的使用:
使用实现runnable接口来实现多个线程:
public class test_runnable02 {
public static void main(String[] args) {
//开启子线程:
thread01 thread01 = new thread01();
thread02 thread02 = new thread02();
Thread td1 = new Thread(thread01);
Thread td2 = new Thread(thread02);
td1.start();
td2.start();
}
}
class thread01 implements Runnable{
//第一个线程
int count=0;
@Override
public void run() {
while (true){
System.out.println("hello thread01" + " "+(++count) +" "+ "当前的进程名字是:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 10){
break;
}
}
}
}
class thread02 implements Runnable{
int count=0;
//第二个线程:
@Override
public void run() {
while (true){
System.out.println("hello thread02" +" "+(++count)+" "+"当前进程名字是:"+ Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 10){
break;
}
}
}
}
hello thread01 1 当前的进程名字是:Thread-0
hello thread02 1 当前进程名字是:Thread-1
hello thread01 2 当前的进程名字是:Thread-0
hello thread02 2 当前进程名字是:Thread-1
hello thread01 3 当前的进程名字是:Thread-0
hello thread02 3 当前进程名字是:Thread-1
hello thread01 4 当前的进程名字是:Thread-0
hello thread02 4 当前进程名字是:Thread-1
hello thread01 5 当前的进程名字是:Thread-0
hello thread02 5 当前进程名字是:Thread-1
hello thread01 6 当前的进程名字是:Thread-0
hello thread02 6 当前进程名字是:Thread-1
hello thread01 7 当前的进程名字是:Thread-0
hello thread02 7 当前进程名字是:Thread-1
hello thread01 8 当前的进程名字是:Thread-0
hello thread02 8 当前进程名字是:Thread-1
hello thread01 9 当前的进程名字是:Thread-0
hello thread02 9 当前进程名字是:Thread-1
hello thread01 10 当前的进程名字是:Thread-0
hello thread02 10 当前进程名字是:Thread-1
继承Thread和实现Runnable接口的区别:
本质上两者没有区别,但是实现Runnable接口更适合多个线程共享资源,并且避免了单继承的机制。
线程常用的方法:
- 第一组:
- 第二组:
守护线程和用户线程:
用户线程:也叫工作线程,当线程的任务执行完后结束;
守护线程:一般是为工作线程服务的。
public class test_Daemon {
public static void main(String[] args) throws InterruptedException {
MyDaemon myDaemon = new MyDaemon();
myDaemon.setDaemon(true);//设置守护线程
myDaemon.start();
//执行主线程:
for (int i=1;i<=10;i++){
Thread.sleep(1000);
System.out.println("主线程在执行:"+i+"次");
}
}
}
class MyDaemon extends Thread{
@Override
public void run() {
for (;;){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("守护线程执行中。。。");
}
}
}