admin管理员组

文章数量:1026989

线程的介绍

线程与进程

进程:

1.指在运行中的程序,例如使用微信就启动一个进程,操作系统就会为 该进程分配内存空间;

2.进程是程序的一次执行的过程,或者是正在运行的一个程序;是动态过程,有它自身的产生、存在和消亡的过程。

线程:

1.线程由进程创建的,是进程的一个实体;

2.一个进程可以拥有多个线程;

3.单线程:同一时刻,只允许执行一个线程;

4.多线程:同一时刻,可以执行多个线程。

并发和并行

并发:

同一时刻,多个任务交替执行;单核CPU实现的多任务就是并发

并行:

同一个时刻,多个任务同时执行,多核CPU可以实现并行

线程的使用

继承Thread创建线程,重写run方法

public static void main(String[] args) throws InterruptedException {
​//创建Dog对象,可以当做线程使用Dog dog = new Dog();//启动线程,执行dog的run方法dog.start();
​//当main线程启动一个子线程 Thread -0,主线程不会阻塞,而是继续执行//主线程和子线程交替执行
​for (int i = 0; i < 80; i++) {System.out.println("主线程 i = " + i + Thread.currentThread().getName());Thread.sleep(1000);}
​
}
//演示通过继承Thread来创建线程
/*说明:
* 1.当一个类继承Thread类,该类就可以做为线程使用
* 2.需要重写run方法,在run方法里面写自己需要实现的结果
* 3.Thread类中的run方法,是Thread类实现了Runnable接口的run方法
* */
​
class Dog extends Thread{
​@Overridepublic void run() {//重写run方法,设置自己需要的实现的结果
​int temp = 0;while (true) {temp ++;//该线程在1s钟,在控制台输出:汪汪汪...System.out.println("汪汪汪..." + "循环次数:" + temp +  Thread.currentThread().getName());//让线程休息1stry {Thread.sleep(1000);//1000 = 1s} catch (InterruptedException e) {e.printStackTrace();}
​//当循环20次后退出循环if(temp == 100){break;}}
​}
}

实现Runnable接口,重写run方法

说明:

1.JAVA是单继承的,在某些情况下一个类可能已经继承了某个父类,这是就不能再去继承Thread类方法来创建线程。

2.因此在上面那种情况下,就只能使用提供的另一个方法创建线程,通过实现Runnable接口创建线程。

public static void main(String[] args) {
​Tiger tiger = new Tiger();
​//调用Thread类来调用start方法去实现Thread thread = new Thread(tiger);thread.start();
​
}
class Tiger implements Runnable{
​int count = 0;
​@Overridepublic void run() {//普通方法while (true){count ++;System.out.println("小老虎..." + count + Thread.currentThread().getName() );
​try {Thread.sleep(1000);//延时1s} catch (InterruptedException e) {e.printStackTrace();}
​if(count == 20){break;}}
​}
}

使用jconsole监控进程执行情况

多个子线程案例

public static void main(String[] args) {
​//在main线程中启动两个子线程Banana banana = new Banana();Thread thread = new Thread(banana);thread.start();
​Apple apple = new Apple();Thread thread1 = new Thread(apple);thread1.start();
}
//每隔1s输出,且输出100次
class Banana implements Runnable{
​@Overridepublic void run() {
​int num01 = 0;while (true){num01 ++;System.out.println("Hello World" + num01 + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
​if (num01 == 10){break;}
​}
​}
}
​
//
class Apple implements Runnable{
​@Overridepublic void run() {int num02 = 0;while (true){num02++;
​System.out.println("hi ..." + num02 + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
​if (num02 == 5){break;}
​}
​}
}

继承Thread和实现Runnable接口的区别

  1. 通过继承Thread或者实现Runnable接口来创建线程本质是没有区别的;Thread类的本身就实现了Runnable接口

  2. 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制,建议一般情况下使用Runnable接口

练习题:实现多线程售票问题

public static void main(String[] args) {
​//使用多线程,模拟三个窗口同时售票/* //第一种方法:使用Thread类SellTicket01 sellTicket01 = new SellTicket01();SellTicket01 sellTicket02 = new SellTicket01();SellTicket01 sellTicket03 = new SellTicket01();
​sellTicket01.start();sellTicket02.start();sellTicket03.start();*/
​//第二种方法:实现Runnable接口SellTicket02 sellTicket02 = new SellTicket02();
​Thread thread01 = new Thread(sellTicket02);Thread thread02 = new Thread(sellTicket02);Thread thread03 = new Thread(sellTicket02);
​thread01.start();thread02.start();thread03.start();
​
}
//第一种方法:继承Thread
class SellTicket01 extends Thread{
​//总票数100张private static int num = 100;
​@Overridepublic void run() {
​while (true){if (num <= 0){System.out.println("票已售完...");break;}
​--num;System.out.println("售票处:" + Thread.currentThread().getName() + "\t" + "售出一张票" + "\t" + "剩余票数=" + num);//延时1stry {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
	//第二种方法:实现Runnable接口
//第一种方法:继承Thread
class SellTicket02 implements Runnable{//总票数100张private  int num = 100;@Overridepublic void run() {while (true){if (num <= 0){System.out.println("票已售完...");break;}--num;System.out.println("售票处:" + Thread.currentThread().getName() + "\t" +"售出一张票" + "\t" + "剩余票数=" + num);//延时1stry {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

通知程序退出(程序终止)

1.当线程完成任务后,会自动退出

2.可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

public static void main(String[] args) throws InterruptedException {Peach peach = new Peach();peach.start();//先延时10s,将线程停止退出Thread.sleep(10*1000);//停止线程peach.setLoop(false);}
class Peach extends Thread{private int num = 0;private boolean loop = true;//可修改looppublic void setLoop(boolean loop) {this.loop = loop;}@Overridepublic void run() {while (loop){num ++;System.out.println("Peach线程正在执行..." + "\t"+Thread.currentThread().getName() + "\t" +num);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

线程中断

1.setName //设置线程名称,使与参数name相同

2.getName //返回该线程的名称

3.start //使该线程开始执行

4.run //调用线程对象run方法

5.setPriority //更改线程的优先级

6.getPriority //获取线程的优先级

7.sleep //在指定的毫秒数内让当前正在执行的线程休眠(暂时执行)

8.interrupt //中断线程

注意:

1.start底层会创建新的线程,调用run,run就是一个方法的调用,不会启动新的线程

2.线程优先级的范围:MAX_PRIORITY = 10 ;MIN_PRIORITY = 1;NORM_PRIORITY = 5

3.interrupt,中断程序;并未使得程序结束只是暂停;一般用于中断正在休眠的线程

4.sleep;线程的静态方法。使得当前线程休眠

public static void main(String[] args) throws InterruptedException {Lemon lemon = new Lemon();lemon.setName("线程01");//修改线程名称lemon.setPriority(Thread.MIN_PRIORITY);//设置优先级:最低lemon.start();System.out.println(lemon.getName());for(int j = 0 ;j < 5;j++){Thread.sleep(1000);System.out.println("hello..." + j);}lemon.interrupt();//执行到中断方法,就会中断lemon线程的休眠}
class Lemon extends Thread{@Overridepublic void run() {while (true) {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "吃柠檬..." + i);}System.out.println(Thread.currentThread().getName() + "吃柠檬..." + "休眠中...");try {Thread.sleep(50 * 1000);} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "吃柠檬..." + "被interrupt ...");}}}
}

线程插队

1.yield:线程的礼让

让出CPU,让其他线程执行,但礼让的时间不确定,所以也不一定成功

2.join:线程插入

插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务

public static void main(String[] args) throws InterruptedException {Mango mango = new Mango();mango.start();for (int i = 0; i < 10; i++) {Thread.sleep(1000);System.out.println(Thread.currentThread().getName()+ "\t" + "吃猕猴桃..." +"\t" + i);if (i == 5){System.out.println("主线程让子线程先执行完...");mango.join();//插队处理:让子线程提前执行//Thread.yield();//让子线程提前执行,但不一定成功}}}
class Mango extends Thread{int num = 0;@Overridepublic void run() {while (true) {for (int i = 0; i < 10; i++) {num ++;try {Thread.sleep(1 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "\t" + "吃芒果..." + 									"\t" + i);}if (num == 20){break;}}}
}

线程插队练习:

1.主线程每隔1s,输出hi,一共10次 2.当输出到hi 5时,启动一个子线程(要求 实现Runnable),每隔1s输出hello,等该线程输出10次hello后,退出 3.主线程继续输出hi,直到主线程退出.

public static void main(String[] args) throws InterruptedException {Almond almond = new Almond();Thread thread = new Thread(almond);for (int i = 0; i < 10; i++) {Thread.sleep(1000);System.out.println("线程:" + Thread.currentThread().getName() + "\t" + "hi..."+"\t" + i);if (i == 5){System.out.println("允许子线程执行...");thread.start();//开启子线程thread.join();//将所有空间给子线程执行}}}
//定义一个类并实现Runnable接口
class Almond implements Runnable{int num = 0;@Overridepublic void run() {while (true){num++;try {Thread.sleep(1000);System.out.println("线程:" + Thread.currentThread().getName()+"\t" + "hello..." + "\t" + num);} catch (InterruptedException e) {e.printStackTrace();}if (num == 10){break;}}}
}

守护线程

用户线程和守护线程

1.用户线程:就是工作线程,当线程的任务执行完或通知方式结束

2.守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束

3.常见的守护线程:垃圾回收机制

public static void main(String[] args) throws InterruptedException {Grape grape = new Grape();//1.如果希望当main线程结束后,子线程自动结束//2.只需要将子线程设为守护线程grape.setDaemon(true);//将子线程设为守护线程grape.start();for (int i = 0; i < 10; i++) {//主线程System.out.println("线程:" + Thread.currentThread().getName() + "\t" + "吃猕猴桃" +"\t" + i);Thread.sleep(1000);}}
class Grape extends Thread{int num = 0;@Overridepublic void run() {while (true) {num ++;try {Thread.sleep(1 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "\t" + "吃葡萄..."+ "\t" + num);}}
}

线程的介绍

线程与进程

进程:

1.指在运行中的程序,例如使用微信就启动一个进程,操作系统就会为 该进程分配内存空间;

2.进程是程序的一次执行的过程,或者是正在运行的一个程序;是动态过程,有它自身的产生、存在和消亡的过程。

线程:

1.线程由进程创建的,是进程的一个实体;

2.一个进程可以拥有多个线程;

3.单线程:同一时刻,只允许执行一个线程;

4.多线程:同一时刻,可以执行多个线程。

并发和并行

并发:

同一时刻,多个任务交替执行;单核CPU实现的多任务就是并发

并行:

同一个时刻,多个任务同时执行,多核CPU可以实现并行

线程的使用

继承Thread创建线程,重写run方法

public static void main(String[] args) throws InterruptedException {
​//创建Dog对象,可以当做线程使用Dog dog = new Dog();//启动线程,执行dog的run方法dog.start();
​//当main线程启动一个子线程 Thread -0,主线程不会阻塞,而是继续执行//主线程和子线程交替执行
​for (int i = 0; i < 80; i++) {System.out.println("主线程 i = " + i + Thread.currentThread().getName());Thread.sleep(1000);}
​
}
//演示通过继承Thread来创建线程
/*说明:
* 1.当一个类继承Thread类,该类就可以做为线程使用
* 2.需要重写run方法,在run方法里面写自己需要实现的结果
* 3.Thread类中的run方法,是Thread类实现了Runnable接口的run方法
* */
​
class Dog extends Thread{
​@Overridepublic void run() {//重写run方法,设置自己需要的实现的结果
​int temp = 0;while (true) {temp ++;//该线程在1s钟,在控制台输出:汪汪汪...System.out.println("汪汪汪..." + "循环次数:" + temp +  Thread.currentThread().getName());//让线程休息1stry {Thread.sleep(1000);//1000 = 1s} catch (InterruptedException e) {e.printStackTrace();}
​//当循环20次后退出循环if(temp == 100){break;}}
​}
}

实现Runnable接口,重写run方法

说明:

1.JAVA是单继承的,在某些情况下一个类可能已经继承了某个父类,这是就不能再去继承Thread类方法来创建线程。

2.因此在上面那种情况下,就只能使用提供的另一个方法创建线程,通过实现Runnable接口创建线程。

public static void main(String[] args) {
​Tiger tiger = new Tiger();
​//调用Thread类来调用start方法去实现Thread thread = new Thread(tiger);thread.start();
​
}
class Tiger implements Runnable{
​int count = 0;
​@Overridepublic void run() {//普通方法while (true){count ++;System.out.println("小老虎..." + count + Thread.currentThread().getName() );
​try {Thread.sleep(1000);//延时1s} catch (InterruptedException e) {e.printStackTrace();}
​if(count == 20){break;}}
​}
}

使用jconsole监控进程执行情况

多个子线程案例

public static void main(String[] args) {
​//在main线程中启动两个子线程Banana banana = new Banana();Thread thread = new Thread(banana);thread.start();
​Apple apple = new Apple();Thread thread1 = new Thread(apple);thread1.start();
}
//每隔1s输出,且输出100次
class Banana implements Runnable{
​@Overridepublic void run() {
​int num01 = 0;while (true){num01 ++;System.out.println("Hello World" + num01 + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
​if (num01 == 10){break;}
​}
​}
}
​
//
class Apple implements Runnable{
​@Overridepublic void run() {int num02 = 0;while (true){num02++;
​System.out.println("hi ..." + num02 + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
​if (num02 == 5){break;}
​}
​}
}

继承Thread和实现Runnable接口的区别

  1. 通过继承Thread或者实现Runnable接口来创建线程本质是没有区别的;Thread类的本身就实现了Runnable接口

  2. 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制,建议一般情况下使用Runnable接口

练习题:实现多线程售票问题

public static void main(String[] args) {
​//使用多线程,模拟三个窗口同时售票/* //第一种方法:使用Thread类SellTicket01 sellTicket01 = new SellTicket01();SellTicket01 sellTicket02 = new SellTicket01();SellTicket01 sellTicket03 = new SellTicket01();
​sellTicket01.start();sellTicket02.start();sellTicket03.start();*/
​//第二种方法:实现Runnable接口SellTicket02 sellTicket02 = new SellTicket02();
​Thread thread01 = new Thread(sellTicket02);Thread thread02 = new Thread(sellTicket02);Thread thread03 = new Thread(sellTicket02);
​thread01.start();thread02.start();thread03.start();
​
}
//第一种方法:继承Thread
class SellTicket01 extends Thread{
​//总票数100张private static int num = 100;
​@Overridepublic void run() {
​while (true){if (num <= 0){System.out.println("票已售完...");break;}
​--num;System.out.println("售票处:" + Thread.currentThread().getName() + "\t" + "售出一张票" + "\t" + "剩余票数=" + num);//延时1stry {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
	//第二种方法:实现Runnable接口
//第一种方法:继承Thread
class SellTicket02 implements Runnable{//总票数100张private  int num = 100;@Overridepublic void run() {while (true){if (num <= 0){System.out.println("票已售完...");break;}--num;System.out.println("售票处:" + Thread.currentThread().getName() + "\t" +"售出一张票" + "\t" + "剩余票数=" + num);//延时1stry {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

通知程序退出(程序终止)

1.当线程完成任务后,会自动退出

2.可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

public static void main(String[] args) throws InterruptedException {Peach peach = new Peach();peach.start();//先延时10s,将线程停止退出Thread.sleep(10*1000);//停止线程peach.setLoop(false);}
class Peach extends Thread{private int num = 0;private boolean loop = true;//可修改looppublic void setLoop(boolean loop) {this.loop = loop;}@Overridepublic void run() {while (loop){num ++;System.out.println("Peach线程正在执行..." + "\t"+Thread.currentThread().getName() + "\t" +num);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

线程中断

1.setName //设置线程名称,使与参数name相同

2.getName //返回该线程的名称

3.start //使该线程开始执行

4.run //调用线程对象run方法

5.setPriority //更改线程的优先级

6.getPriority //获取线程的优先级

7.sleep //在指定的毫秒数内让当前正在执行的线程休眠(暂时执行)

8.interrupt //中断线程

注意:

1.start底层会创建新的线程,调用run,run就是一个方法的调用,不会启动新的线程

2.线程优先级的范围:MAX_PRIORITY = 10 ;MIN_PRIORITY = 1;NORM_PRIORITY = 5

3.interrupt,中断程序;并未使得程序结束只是暂停;一般用于中断正在休眠的线程

4.sleep;线程的静态方法。使得当前线程休眠

public static void main(String[] args) throws InterruptedException {Lemon lemon = new Lemon();lemon.setName("线程01");//修改线程名称lemon.setPriority(Thread.MIN_PRIORITY);//设置优先级:最低lemon.start();System.out.println(lemon.getName());for(int j = 0 ;j < 5;j++){Thread.sleep(1000);System.out.println("hello..." + j);}lemon.interrupt();//执行到中断方法,就会中断lemon线程的休眠}
class Lemon extends Thread{@Overridepublic void run() {while (true) {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "吃柠檬..." + i);}System.out.println(Thread.currentThread().getName() + "吃柠檬..." + "休眠中...");try {Thread.sleep(50 * 1000);} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "吃柠檬..." + "被interrupt ...");}}}
}

线程插队

1.yield:线程的礼让

让出CPU,让其他线程执行,但礼让的时间不确定,所以也不一定成功

2.join:线程插入

插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务

public static void main(String[] args) throws InterruptedException {Mango mango = new Mango();mango.start();for (int i = 0; i < 10; i++) {Thread.sleep(1000);System.out.println(Thread.currentThread().getName()+ "\t" + "吃猕猴桃..." +"\t" + i);if (i == 5){System.out.println("主线程让子线程先执行完...");mango.join();//插队处理:让子线程提前执行//Thread.yield();//让子线程提前执行,但不一定成功}}}
class Mango extends Thread{int num = 0;@Overridepublic void run() {while (true) {for (int i = 0; i < 10; i++) {num ++;try {Thread.sleep(1 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "\t" + "吃芒果..." + 									"\t" + i);}if (num == 20){break;}}}
}

线程插队练习:

1.主线程每隔1s,输出hi,一共10次 2.当输出到hi 5时,启动一个子线程(要求 实现Runnable),每隔1s输出hello,等该线程输出10次hello后,退出 3.主线程继续输出hi,直到主线程退出.

public static void main(String[] args) throws InterruptedException {Almond almond = new Almond();Thread thread = new Thread(almond);for (int i = 0; i < 10; i++) {Thread.sleep(1000);System.out.println("线程:" + Thread.currentThread().getName() + "\t" + "hi..."+"\t" + i);if (i == 5){System.out.println("允许子线程执行...");thread.start();//开启子线程thread.join();//将所有空间给子线程执行}}}
//定义一个类并实现Runnable接口
class Almond implements Runnable{int num = 0;@Overridepublic void run() {while (true){num++;try {Thread.sleep(1000);System.out.println("线程:" + Thread.currentThread().getName()+"\t" + "hello..." + "\t" + num);} catch (InterruptedException e) {e.printStackTrace();}if (num == 10){break;}}}
}

守护线程

用户线程和守护线程

1.用户线程:就是工作线程,当线程的任务执行完或通知方式结束

2.守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束

3.常见的守护线程:垃圾回收机制

public static void main(String[] args) throws InterruptedException {Grape grape = new Grape();//1.如果希望当main线程结束后,子线程自动结束//2.只需要将子线程设为守护线程grape.setDaemon(true);//将子线程设为守护线程grape.start();for (int i = 0; i < 10; i++) {//主线程System.out.println("线程:" + Thread.currentThread().getName() + "\t" + "吃猕猴桃" +"\t" + i);Thread.sleep(1000);}}
class Grape extends Thread{int num = 0;@Overridepublic void run() {while (true) {num ++;try {Thread.sleep(1 * 1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "\t" + "吃葡萄..."+ "\t" + num);}}
}

本文标签: 线程的介绍