多线程初步
概念
程序
是为了完成特定任务,用某种语言编写的一组指令的集合
进程
- 进程是运行中的程序,比如我们使用 QQ,就启动了一个进程,操作系统就会为该进程分配内存空间,当我们使用微信,有启动了一个进程,操作系统将为微信分配新的内存空间
- 进程是程序的一次执行过程,或是正在运行的一个程序,是动态过程,有它自身的产生、存在和消亡的过程
线程
- 线程是由进程创建的,是进程的一个实体
- 一个进程可以拥有多个线程
单线程
同一个时刻,只允许执行一个线程
多线程
同一个时刻,可以执行多个线程
并发
同一个时刻,多个任务交替执行,造成一种“貌似同时”的错觉,简单来说,单核 CPU 是实现的多任务就是并发
并行
同一个时刻,多个任务同时执行,多核 CPU 可以实现并行
线程基本使用
- 继承 Thread 类, 重写 run 方法
- 实现 Runnable 接口,重写 run 方法
真正实现多线程效果的,是start0(),而不是 run()
package com.bbedu.threadUse;
public class Thread03 {
public static void main(String[] args) {
Thread thread1 = new Thread(new T1());
Thread thread2 = new Thread(new T2());
thread1.start();
thread2.start();
}
}
class T1 implements Runnable {
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("hello~ " + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 30) {
break;
}
}
}
}
class T2 implements Runnable {
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("hi~ " + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 40) {
break;
}
}
}
}
Thread 和 Runnable 的区别
线程常用方法
练习
package com.bbedu.method;
public class ThreadMethodExercise {
public static void main(String[] args) throws InterruptedException {
T2 t2 = new T2();
for (int i = 1; i <= 10; i++) {
System.out.println("hi " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 5) {
t2.start();
t2.join();
}
}
System.out.println("主线程结束...");
}
}
class T2 extends Thread{
int num = 0;
@Override
public void run() {
while (num < 10) {
System.out.println("hello " + (++num));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("子线程结束...");
}
}
线程七大状态
Synchronized
互斥锁
- Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
- 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,能有一个线程访问该对象。
- 关键字synchronized来与对象的互斥锁联系。当某个对象 synchronized 修饰时,表明该对象在任一时刻只能由一个线程访问
- 同步的局限性:导致程序的执行效率要降低
- 同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)
- 同步方法(静态的)的锁为当前类本身。
细节
- 同步方法如果没有使用static修饰:默认锁对象为this
- 如果方法使用static修饰,默认锁对象:当前类.class
- 实现的落地步骤:
需要先分析上锁的代码选择同步代码块或同步方法
要求多个线程的锁对象为同一个即可!
作业
package com.bbedu.homework;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
public class Homework01 {
public static void main(String[] args) {
T01 t01 = new T01();
T02 t02 = new T02(t01);
t01.start();
t02.start();
}
}
class T01 extends Thread {
private boolean loop = true;
@Override
public void run() {
while (loop) {
System.out.println((int)(Math.random() * 100 + 1));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
class T02 extends Thread {
private T01 t01;
private Scanner scanner = new Scanner(System.in);
public T02(T01 t01) {
this.t01 = t01;
}
@Override
public void run() {
while (true) {
System.out.println("输入q结束");
char c = scanner.next().toUpperCase().charAt(0);
if (c == 'Q') {
t01.setLoop(false);
System.out.println("t01退出");
break;
}
}
}
}
package com.bbedu.homework;
public class Homework02 {
public static void main(String[] args) {
Withdraw withdraw = new Withdraw();
Thread thread1 = new Thread(withdraw);
Thread thread2 = new Thread(withdraw);
thread1.start();
thread2.start();
}
}
class Withdraw implements Runnable {
static final Object obj = new Object();
private static int total = 10000;
private boolean loop = true;
public void withdraw() {
synchronized (obj) {
if (total <= 0) {
loop = false;
return;
}
total -= 1000;
System.out.println("用户 " + Thread.currentThread().getName() +
" 取出1000元" + " 剩余=" + total);
}
}
@Override
public void run() {
while (loop) {
withdraw();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
评论