目录
一、线程介绍
1.程序
为完成特定任务,用某种语言编写的一组指令的集合。简单来说就是我们写的代码。
2.线程相关概念
1)什么是进程?
2)什么是线程?
3)单线程&多线程
4)并发&并行
查看Cpu处理个数:
/**
* @author: 程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:
*/
public class CpuNum {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
int i = runtime.availableProcessors();
System.out.println(i);//8
}
}
二、线程使用
创建线程的两种方式:
Ⅰ.继承Thread类,重写run()方法
Ⅱ.实现Runnable接口,重写run()方法
1.继承Thread类
继承关系图:
应用案例:编写一个线程,每个一秒,控制台输出“我是一只可爱喵”,并用Jconsole监控线程执行情况。
/**
* @author: 程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:
*/
public class Thread01 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start();
}
}
class Cat extends Thread{
@Override
public void run() {
int i=0;
while(true){
System.out.println("我是一只可爱喵" + (++i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i==80)
break;
}
}
}
输出:
我是一只可爱喵1
我是一只可爱喵2
我是一只可爱喵3
...
我是一只可爱喵79
我是一只可爱喵80
2.多线程机制
/**
* @author: 程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:
*/
public class Thread02 {
public static void main(String[] args) {
Cat2 cat = new Cat2();
cat.start();
System.out.println("主线程继续执行" + Thread.currentThread().getName());
for (int i = 1; i <= 60; i++) {
System.out.println("我是主线程" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Cat2 extends Thread{
@Override
public void run() {
int i=0;
while(true){
System.out.println("我是一只可爱喵" + (++i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i==80)
break;
}
}
}
输出:
主线程继续执行main
我是一只可爱喵1
我是主线程1
我是主线程2
我是一只可爱喵2
我是一只可爱喵3
...
我是一只可爱喵79
我是一只可爱喵80
为什么是start?
直接调run方法行不行?
package com.feiyang.basic13;
/**
* @author: 程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:
*/
public class Thread02 {
public static void main(String[] args) {
Cat2 cat = new Cat2();
cat.start();
//cat.run();
System.out.println("主线程继续执行" + Thread.currentThread().getName());
for (int i = 1; i <= 60; i++) {
System.out.println("我是主线程" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Cat2 extends Thread{
@Override
public void run() {
int i=0;
while(true){
System.out.println("我是一只可爱喵" + (++i) + ",线程名:" +Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i==80)
break;
}
}
}
演示:cat.start();
输出:
主线程继续执行main
我是一只可爱喵1,线程名:Thread-0
我是主线程1
我是一只可爱喵2,线程名:Thread-0
我是主线程2
我是主线程3
我是一只可爱喵3,线程名:Thread-0
我是一只可爱喵4,线程名:Thread-0
演示:cat.run();
输出:
我是一只可爱喵1,线程名:main
我是一只可爱喵2,线程名:main
我是一只可爱喵3,线程名:main
start创建新线程,直接调用run方法并不会创建新线程
多线程机制
①main方法启动后会进入start方法
public synchronized void start() {
start0();
}
②start方法中有start0()方法,该方法是真正的实现多线程,
start0是native,本地方法,由JVM调用,底层是c/c++实现
private native void start0();
2.实现Runnable接口
说明
①java是单继承的,某些情况下,一个类已经继承了某个父类,此时再继承Thread类显然是不可能的。
②java设计者提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程
/**
* @author:程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:
*/
public class Thread02 {
public static void main(String[] args) {
T2 t2 = new T2();
Thread thread = new Thread(t2);
thread.start();
}
}
class T2 implements Runnable{
int times = 0;
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hi!" + (++times));
if(times==10){
break;
}
}
}
}
输出:
hi!1
hi!2
hi!3
...
hi!9
hi!10
使用代理模式模拟
/**
* @author:程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:使用代理模式模拟
*/
public class ThreadProxyAgency {
public static void main(String[] args) {
Dog dog = new Dog();
ThreadProxy threadProxy = new ThreadProxy(dog);
threadProxy.start();
}
}
class ThreadProxy implements Runnable{
private Runnable target = null;
@Override
public void run() {
if(target != null){
target.run();
}
}
public ThreadProxy(Runnable target){
this.target = target;
}
public void start(){
start0();
}
public void start0(){
run();
}
}
class Dog implements Runnable{
int times = 0;
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hi!" + (++times));
if(times==10){
break;
}
}
}
}
输出:
hi!1
hi!2
hi!3
...
hi!9
hi!10
多线程执行案例
package com.feiyang.basic13;
/**
* @author:程序员飞扬
* @公众hao:程序员飞扬
* @description:
*/
public class Thread04 {
public static void main(String[] args) {
T3 t3 = new T3();
T4 t4 = new T4();
Thread thread1 = new Thread(t3);
Thread thread2 = new Thread(t4);
thread1.start();
thread2.start();
}
}
class T3 implements Runnable{
int times1;
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hello,wold" + (++times1));
if(times1 == 10){
break;
}
}
}
}
class T4 implements Runnable{
int times2;
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hi" + (++times2) );
if(times2 == 5){
break;
}
}
}
}
输出:
hello,wold1
hi1
hi2
hello,wold2
hi3
hello,wold3
hello,wold4
hi4
hello,wold5
hi5
hello,wold6
hello,wold7
hello,wold8
hello,wold9
hello,wold10
3.线程如何理解
4.继承Thread和实现Runnable区别
5.售票案例
会有超卖,重复卖问题,下章会讲如何解决
/**
* @author:程序员飞扬
* @公众hao:程序员飞扬
* @description:
*/
public class SellTicket {
public static void main(String[] args) {
Sell sell = new Sell();
new Thread(sell).start();
new Thread(sell).start();
new Thread(sell).start();
}
}
class Sell implements Runnable{
static int ticket = 100;
@Override
public void run() {
while(true){
if(ticket <= 0){
break;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("窗口" + Thread.currentThread().getName()+"卖出了一张票,剩余" + (--ticket) );
}
}
}
6.线程退出
/**
* @author:程序员飞扬
* @公众hao:程序员飞扬
* @description:
*/
public class ThreadExit {
public static void main(String[] args) {
T t = new T();
Thread thread = new Thread(t);
thread.start();
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.setExit(false);
System.out.println("Thread退出了");
}
}
class T implements Runnable{
int times2;
private boolean exit = true;
@Override
public void run() {
while(exit){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread继续运行" + (++times2) );
}
}
public void setExit(boolean exit) {
this.exit = exit;
}
}
输出:
Thread继续运行1
Thread继续运行2
Thread继续运行3
Thread继续运行4
Thread继续运行5
Thread继续运行6
Thread退出了
三、线程常用方法
1.线程中断
/**
* @author: 程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:
*/
public class ThreadMethod01 {
public static void main(String[] args) throws InterruptedException {
T1 t1 = new T1();
t1.setName("老王");
t1.setPriority(Thread.MIN_PRIORITY);
t1.start();
for (int i = 1; i <= 3; i++) {
Thread.sleep(1000);
System.out.println(i + "秒");
}
System.out.println("都休息三秒了,起来继续吃~");
t1.interrupt();
}
}
class T1 extends Thread{
int count = 0;
@Override
public void run() {
while(true){
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + "开始吃包子~" + i);
}
try {
System.out.println(Thread.currentThread().getName()+"太累了休息5秒~");
Thread.sleep(5*1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"被中断了");
}
count++;
if(count==3){
System.out.println("吃撑了,不吃了哈~");
break;
}
}
}
}
输出:
老王开始吃包子~1
老王开始吃包子~2
老王开始吃包子~3
老王太累了休息5秒~
1秒
2秒
3秒
都休息三秒了,起来继续吃~
老王被中断了
老王开始吃包子~1
老王开始吃包子~2
老王开始吃包子~3
老王太累了休息5秒~
老王开始吃包子~1
老王开始吃包子~2
老王开始吃包子~3
老王太累了休息5秒~
吃撑了,不吃了哈~
2.线程插队
/**
* @author: 程序员飞扬
* @公众hao:程序员飞扬
* @微xin:haris7799
* @description:
*/
public class ThreadMethod02 {
public static void main(String[] args) throws InterruptedException {
T5 t5 = new T5();
t5.start();
for (int i = 1; i <= 5; i++) {
Thread.sleep(1000);
System.out.println("小弟吃包子" + i);
if(i==3){
System.out.println("小弟已经吃了3了个,让老大先吃饱~~~");
t5.join();//线程插队,相当于让t5先执行完
//Thread.yield();//礼让,但不一定礼让成功
}
}
}
}
class T5 extends Thread{
@Override
public void run() {
try {
for (int i = 1; i <= 8; i++) {
System.out.println("老大开始吃包子" + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
}
}
输出:
老大开始吃包子1
老大开始吃包子2
小弟吃包子1
老大开始吃包子3
小弟吃包子2
老大开始吃包子4
小弟吃包子3
小弟已经吃了3了个,让老大先吃饱~~~
老大开始吃包子5
老大开始吃包子6
老大开始吃包子7
老大开始吃包子8
小弟吃包子4
小弟吃包子5
练习题:
/**
* @author:程序员飞扬
* @公众hao:程序员飞扬
* @description:
*/
public class ThreadMethodExcrcise {
public static void main(String[] args) throws InterruptedException {
T6 t6 = new T6();
Thread t = new Thread(t6);
for (int i = 1; i <= 10; i++) {
System.out.println("hi" + i);
Thread.sleep(1000);
if(i==5){
t.start();
t.join();
}
if(i==10){
System.out.println("主线程结束");
}
}
}
}
class T6 implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println("hello" + i);
if(i==10){
System.out.println("子线程结束");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
hi1
hi2
hi3
hi4
hi5
hello1
hello2
hello3
hello4
hello5
hello6
hello7
hello8
hello9
hello10
子线程结束
hi6
hi7
hi8
hi9
hi10
主线程结束
3.守护线程
setDaemon(true)
/**
* @author:程序员飞扬
* @公众hao:程序员飞扬
* @description:
*/
public class ThreadMethod03 {
public static void main(String[] args) throws InterruptedException {
MyDaemonThread myDaemonThread = new MyDaemonThread();
myDaemonThread.setDaemon(true);
myDaemonThread.start();
for (int i = 1; i <= 50 ; i++) {
Thread.sleep(50);
System.out.println("宝宝在辛苦的拍电影。。。");
}
}
}
class MyDaemonThread extends Thread{
@Override
public void run() {
for(;;){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("蓉蓉和喆喆在快乐的聊天,哈哈哈~");
}
}
}