Java多线程
概述:本文为Java多线程的基础知识点的第一部分,主要包括,通过继承Thread来实现进程,线程调度,线程控制,run(),start(),join(),sleep(),setDaemon()方法的使用,获取线程名字currentThread(),线程同步,非静态锁,静态方法的锁,Lock锁,生产者与消费者问题,卖票问题。
简介
线程:是进程中的单个顺序控制流,是一条执行路径
- 单线程:一个进程如果只有一条执行路径,则称为单线程程序
- 多线程:一个进程如果有多条执行路径,则称为多线程程序
举例
- 记事本属于单线程程序
- 扫雷属于多线程程序
方式一
方式一:继承Thread类
- 定义一个类MyThread类
- 在MyThread类中重写run()方法
- 创建MyThread类的对象
- 启动线程
两个问题:
- 为什么要重写run()方法?
因为run()是用来封装被线程执行的代码 - run()方法和start()方法的区别?
run():封装线程执行代码,直接调用,相当于普通方法的调用
start():启动线程;然后由JVM调用此线程的run()方法
run()
package com.one.container; public class MyThreadDemo { public static class MyThread extends Thread{ public MyThread(){} public MyThread(String name){ // 自定义一个有参的构成方法 super(name); } @Override public void run() { for (int i = 0; i < 100; ++ i){ System.out.println(getName()+":"+i); } } } public static void main(String[] args){ MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); my1.setName("高铁"); my2.setName("飞机"); my1.run(); // run方法 相当于单线程的 my2.run(); } } }
运行结果:
start()
讲解代码:
package com.one.container; import java.util.Scanner; import java.util.Arrays; public class Main { // 通过继承Thread类来创造属于自己的MyThread public static class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; ++ i){ System.out.println(i); } } } public static void main(String[] args){ // 创建两个对象 MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); // my1.run(); run方法 相当于单线程的 // my2.run(); // 然后调用start方法 my1.start(); my2.start(); } }
运行结果:
设置和获取线程的名称
Thread.currentThread().getName():获取当当前的线程的名称
代码讲解:
public class MyThreadDemo { public static class MyThread extends Thread{ public MyThread(){} public MyThread(String name){ // 自定义一个有参的构成方法 super(name); } @Override public void run() { for (int i = 0; i < 100; ++ i){ System.out.println(getName()+":"+i); } } } public static void main(String[] args){ // 自定义的有参构造方法 不需要直接调用setName设置线程名称 MyThread my1 = new MyThread("高铁"); MyThread my2 = new MyThread("飞机"); my1.start(); my2.start(); // 返回对象前正在执行的线程对象的引用 System.out.println(Thread.currentThread().getName()); } }
运行结果:
线程调度
线程调度
线程有两种调度模型
- 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占有的CPU的时间片
- 抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机一个,优先级高的线程获取的CPU时间片相对多一些
Java使用的抢占式的调度模型
假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令,所以说多线程程序在执行的是有随机性,因为谁抢到CPU的使用权是不一定的
Thread类中设置和获取线程优先级的方法
- public final int getPriority(): 返回此线程的优先级
- public final void setPriority(int new Priority): 更改此线程的优先级
线程默认优先级是5;线程优先级的范围是:1-10
线程优先级高仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到你想要大家结果
public class MyThreadDemo { public static class ThreadPriority extends Thread{ @Override public void run() { for (int i = 0; i < 100; i ++){ System.out.println(getName()+":"+i); } } } public static void main(String[] args){ // 创建进程对象 ThreadPriority tp1 = new ThreadPriority(); ThreadPriority tp2 = new ThreadPriority(); ThreadPriority tp3 = new ThreadPriority(); // public final int getPriority(); // 返回线程的优先级 System.out.println(tp1.getPriority()); System.out.println(tp2.getPriority()); System.out.println(tp3.getPriority()); // 设置进程名字 tp1.setName("高铁"); tp2.setName("飞机"); tp3.setName("汽车"); // public final void setPriority(int newPriority); 更改此线程的优先级 // tp1.setPriority(10000); // System.out.println(Thread.MAX_PRIORITY); // 最高优先级 // System.out.println(Thread.MIN_PRIORITY); // 最小优先级 // System.out.println(Thread.NORM_PRIORITY); // 正常优先级 tp1.setPriority(Thread.NORM_PRIORITY); tp2.setPriority(Thread.MAX_PRIORITY); tp3.setPriority(Thread.MIN_PRIORITY); // 启动线程 tp1.start(); tp2.start(); tp3.start(); } }
运行结果:
线程控制
sleep
学习代码:
public class MyThreadDemo { public static class ThreadSleep extends Thread{ ThreadSleep(){} ThreadSleep(String name){ super(name); } @Override public void run() { for (int i = 0; i < 100; i ++){ System.out.println(getName()+":"+i); try{ Thread.sleep(1000); // 休眠1s } catch (InterruptedException e){ e.printStackTrace(); } } } } public static void main(String[] args){ ThreadSleep ts1 = new ThreadSleep("曹操"); ThreadSleep ts2 = new ThreadSleep("刘备"); ThreadSleep ts3 = new ThreadSleep("孙权"); ts1.start(); ts2.start(); ts3.start(); } }
运行结果:
join
学习代码:
public class MyThreadDemo { public static class ThreadJoin extends Thread{ ThreadJoin(){} ThreadJoin(String name){ super(name); } @Override public void run() { for (int i = 0; i < 10; i ++){ System.out.println(getName()+":"+i); } } } public static void main(String[] args){ ThreadJoin tj1 = new ThreadJoin("路飞"); ThreadJoin tj2 = new ThreadJoin("索隆"); ThreadJoin tj3 = new ThreadJoin("山治"); tj1.start(); try { tj1.join(); // 等路飞 这个线程结束了 下面两个线程才会 // 执行 } catch (InterruptedException e) { e.printStackTrace(); } tj2.start(); tj3.start(); } }
运行结果:
setDaemon
学习代码:
public class MyThreadDemo { public static class ThreadDaemon extends Thread{ ThreadDaemon(){} ThreadDaemon(String name){ super(name); } @Override public void run() { for (int i = 0; i < 10; i ++){ System.out.println(getName()+":"+i); } } } public static void main(String[] args){ ThreadDaemon td1 = new ThreadDaemon("善毅"); ThreadDaemon td2 = new ThreadDaemon("山之助"); // 设置主线程名字为炭之郎 Thread.currentThread().setName("炭之郎"); // 设置守护线程 td1.setDaemon(true); // 要写在start的前面 td2.setDaemon(true); // 鬼灭之刃三人组 炭之郎死后 二位小弟也要一同共赴黄泉 td1.start(); td2.start(); for (int i = 0; i < 10; ++ i){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
运行结果:
方式二
学习代码:
public class MyThreadDemo { // 通过继承Runnable接口来实现多线程 public static class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 10; ++ i){ // 获取当前进程的名字 System.out.println(Thread.currentThread().getName()+":"+i); } } } public static void main(String[] args){ MyRunnable my = new MyRunnable(); Thread t1 = new Thread(my, "高铁"); Thread t2 = new Thread(my, "飞机"); t1.start(); t2.start(); } }
运行结果:
Java多线程(全知识点)(下):https://developer.aliyun.com/article/1419403