目录
1. 程序、进程、线程
1.1 概念
?1.2 单核CPU和多核CPU
1.3 多线程优点(单核为何需要多线程?)
?
1.4 何时需要多线程?
1.5 辨析1(能拿一条线画出来就不是多线程)
??
1.6?代码示例
1.6.1 线程创建方式1(alt+enter快速造对象)
1.6.2 创建两个线程,匿名子类
1.6.3 线程的创建方式2(Runnable接口)
1.6.4 两者对比
1.7 Thread类的方法
1.8 线程的优先级
1.9 线程的分类
2 多窗口卖票
2.1 使用继承Thread类的方式
2.3 使用实现Runnable接口的方式(p)
2.4 接口方法更好
1. 程序、进程、线程
1.1 概念
程序:一段静态代码。
进程:运行中的程序,有生命周期。
线程 (thread) (室友+厨房):一个进程里面可以有多个线程,并行执行。main就对应一个线程。
?1.2 单核CPU和多核CPU
单核:主频高,轮流执行各个线程,伪多线程。
多核:根据不同业务启动不同的核。
并行与并发:
1.3 多线程优点(单核为何需要多线程?)
1.4 何时需要多线程?
1.5 辨析1(能拿一条线画出来就不是多线程)
?
1.6?代码示例
1.6.1 线程创建方式1(alt+enter快速造对象)
问题一:我们启动一个线程,必须调用start(),不能调用run()的方式启动线程。 问题二:如果再启动一个线程,必须重新创建一个Thread子类的对象,调用此对象的start().
package com.lee.java;
/**
* 多线程的创建,方式一:继承于Thread类
* 1. 创建一个继承于Thread类的子类
* 2. 重写Thread类的run():将线程要做的事情放到方法体当中
* 3. 创建Thread类的子类对象:在主线程
* 4. 通过此对象调用start()
*
* 例子:遍历100以内的所有偶数
*
* @author Lee
* @create 2021-08-11 23:33
*/
//1. 创建一个继承于Thread类的子类
class MyThread extends Thread {
@Override
public void run() {
//2. 重写Thread类的run():将线程要做的事情放到方法体当中
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//3. 创建Thread类的子类对象:在主线程
//主线程造对象(婴儿):
MyThread t1 = new MyThread(); //alt+enter 自动创建对象
//4. 通过此对象调用start():1.启动当前线程 2.调用当前线程的run()
//主线程调方法:
t1.start();
//Q1:我们不能通过直接调用run()的方式启动线程
// t1.run();//都是主线程
//问题二:在启动一个线程,遍历100以内的偶数、
// t1.start();//对于一个线程只能start一次
MyThread t2 = new MyThread();
t2.start();
//和子线程并行执行,输出位置不确定
//如下操作仍然是main中执行
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i + "******main******");
}
}
}
}
1.6.2 创建两个线程,匿名子类
package com.lee.exer;
/**
* 练习:创建两个线程。一个线程遍历100以内的偶数,另一个遍历100以内的奇数。
* @author Lee
* @create 2021-08-12 22:08
*/
public class ThreadDemo extends Thread{
public static void main(String[] args) {
// OddThread t1 = new OddThread();
// t1.start();
//
// EvenThread t2 = new EvenThread();
// t2.start();
//创建Thread类的匿名子类
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}.start();
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}.start();
}
}
class OddThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
class EvenThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
1.6.3 线程的创建方式2(Runnable接口)
package com.lee.java;
/**
* 创建多线程的方式二:实现Runnable接口
* 1.创建一个实现了Runnable接口的类
* 2.实现类去实现Runnable中的抽象方法:Run()
* 3.创建Thread类的子类的对象
* 4.通过此对象调用start()
* @author Lee
* @create 2021-08-15 22:49
*/
class MThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
//3. 创建实现类的对象(共用)
MThread mThread = new MThread();
//4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread t1 = new Thread(mThread);
t1.setName("线程1");
//5. 通过Thread类的对象调用start():① 启动线程 ②调用当前线程的run()-->调用了Runnable类型的target的run()
t1.start();
//再启动一个线程
Thread t2 = new Thread(mThread);
t2.start();
}
}
1.6.4 两者对比
* 开发中:优先选择:实现Runnable接口的方式 * 原因:
1.? 实现的方式没类的单继承性的局限性 2. 实现的方式更适合来处理多个线程共享数据的情况。 * 联系:public class Thread implements Runnable * 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。 ? ? ? ? ? 目前两种方式,要想启动线程,都是调用的Thread类中的start()。
1.7 Thread类的方法
?重写方法抛出的异常不能比原来的更大
1.8 线程的优先级
?优先级高并不意味着先执行,高概率先执行。
package com.lee.java;
/**
*
*
* @author Lee
* @create 2021-08-12 22:34
*/
class HelloThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" +i);
}
if (i % 10 == 0) {
this.yield();//this是当前类的对象,即当前线程。释放当前cpu的执行权
// Thread.currentThread().yield();//和上面的写法等价
}
}
}
//利用构造器命名
public HelloThread(String name){
super(name);
}
}
public class ThreadMethodTest {
public static void main(String[] args) {
//给子线程起名+运行
// 1.构造器命名
HelloThread h1 = new HelloThread("线程1");
// 2.setname 命名
// HelloThread h1 = new HelloThread();
// h1.setName("线程1");
h1.start();
// 3.设置线程的优先级
h1.setPriority(Thread.MAX_PRIORITY);
//给主线程起名
Thread.currentThread().setName("主线程");
//给主线程设置优先级
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);
}
}
}
}
1.9 线程的分类
一种是守护线程,一种是用户线程。
2 多窗口卖票
2.1 使用继承Thread类的方式
package com.lee.java;
/**
* 例子:创建三个窗口卖票,总票数为100张
* @author Lee
* @create 2021-08-13 22:27
*/
class Window extends Thread {
// private int ticket = 100;//每个对象有自己的100张票
private static int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0){
System.out.println(getName() + ":卖票,票号为:" + ticket);
//三个窗口同时在卖第100张票
ticket--;
} else {
break;
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window t1 = new Window();
Window t2 = new Window();
Window t3 = new Window();
t1.setName("售票窗口1:");
t2.setName("售票窗口2:");
t3.setName("售票窗口3:");
t1.start();
t2.start();
t3.start();
}
}
2.3 使用实现Runnable接口的方式(p)
package com.lee.java;
/**
* @author Lee
* @create 2021-08-15 23:19
*/
class Window1 implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0){
System.out.println(Thread.currentThread().getName()
+ "卖票,票号为:" + ticket);
ticket--;
}else {
break;
}
}
}
}
public class WindowTest1 {
public static void main(String[] args) {
Window1 w = new Window1();
Thread w1 = new Thread(w);
Thread w2 = new Thread(w);
Thread w3 = new Thread(w);
w1.start();
w2.start();
w3.start();
}
}
2.4 接口方法更好
单继承只能继承一个父类
继承的方式中,要设置static变量
?* 比较创建线程的两种方式。 ?* 开发中:优先选择:实现Runnable接口的方式 ?* 原因:1. 实现的方式没有类的单继承性的局限性 ?* ? ? ?2. 实现的方式更适合来处理多个线程有共享数据的情况。 ?* ?* 联系:public class Thread implements Runnable
继承Thread,Thread实现Runnable。为何不直接实现Runnable。 ?* 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。
|