1.多线程
>程序 进程 线程
程序 : 为完成特定任务,用某种语言编写的一组指令的集合
进程 : 程序的一次执行过程,或是正在内存中运行的应用程序
线程 : 是程序内部的一条执行路径,一个程序中至少有一个线程
>线程调度
分时调度
所有线程轮流使用CPU,并且平均分配每个线程占用的CPU的时间
抢占式调度
让优先级高的线程以较大的概率优先使用CPU,如果线程的优先级相同,那么会随机选择一个
Java使用的是抢占式调度
>并行与并发
并行 : 两个或多个事件同时发生
并发 : 两个或多个时间在同一个时间段发生,交替进行
>单核CPU与多核CPU
单核CPU : 在一个时间单元内,只能执行一个线程的任务
多核CPU : 在一个时间单元内,可以执行多个线程的任务
>创建和启动进程
概述
Thread类的特性
- 每个线程都是通过某个特定的Tread对象的run()方法来完成操作的,因此把run()方法成为线 程执行体
- 通过该Thread对象的start()方法来启动这个线程,而非直接调用run()
- 想要实现多线程,必须在主线程中创建新的线程对象
方式1: 继承Thread类
步骤: 1.定义Thread类的子类,并重写该类的run() 方法,该run()方法的方法体就代表了线程需要完 成的任务
2.创建Thread子类的实例,即创建线程的对象
3.调用该线程对象的start()方法来启动线程
public static void main(String[] args) {
//创建线程的对象
Thread t1 = new Print();
//启动线程
t1.start();
}
class Print extends Thread{
@Override
public void run() {
for(int i = 0;i <= 100;i++)
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
方式2: 实现Runnable接口
步骤:1.定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体是该线程的 线程执行体
2.创建Runnable实现类的实例,并以此实例作为Thread的target参数来创建Thread对象,该 Thread对象才是真正的线程对象
3.调用线程对象的start()方法,启动线程
public static void main(String[] args) {
//创建线程的对象
PrintOu po = new PrintOu();
Thread t1 = new Thread(po);
t1.setName("打印偶数的线程");
t1.start();
}
class PrintOu implements Runnable{
@Override
public void run() {
for(int i = 0;i <= 100;i++){
if(i % 2 == 0)
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
>优先级和相关方法
概述
java中的优先级分为了1~10的十个登记,其中10优先级最高,1优先级最低
子类继承父类优先级默认是5
方法
setPriority 设置优先级
getPriority 获取优先级
getName 获取线程名称
setName 设置线程名称
static currentThread 获取当前线程对象
static sleep 让当前线程进入睡眠状态,参数为毫秒数
>线程控制
JDK1.5之前
线程的生命周期有5种状态: 新建,就绪,运行,阻塞,死亡
JDK1.5及之后
线程的生命周期有6种状态
>线程停止
public class _05_Stop {
public static void main(String[] args) {
Print2 print2 = new Print2();
Thread t1 = new Thread(print2);
t1.start();
//通过stop()方法可以关闭进程 但是不推荐使用 因为可能会造成死锁
//另一种关闭进程的方法 是通过一个标志来实现
try {
Thread.sleep(3000);
print2.flag = false;
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Print2 implements Runnable{
boolean flag = true;
@Override
public void run() {
for(int i = 1;i <= 50;i++) {
if(!flag) {
return;
}
System.out.println(Thread.currentThread().getName() + ":" + i);
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("结束");
}
}
>join
public class _06_Join {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Print3();
Thread t2 = new Print3();
t1.setName("t1的线程");
t2.setName("t2的线程");
//启动线程
t1.start();
t2.start();
//调用join() 可以让t1线程插入到main线程之前
t1.join();
//main线程
for(int i = 1;i <= 50;i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Print3 extends Thread{
@Override
public void run() {
for(int i = 1;i <= 10;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
>yield
public class _07_Yield {
public static void main(String[] args) {
Print4 print4 = new Print4();
Thread t1 = new Thread(print4);
//将t1线程和main线程设置相同的优先级
t1.setPriority(5);
Thread.currentThread().setPriority(5);
//启动t1线程
t1.start();
//main线程
for(int i = 20;i <= 40;i++) {
Thread.yield();
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
class Print4 implements Runnable{
@Override
public void run() {
for(int i = 1;i <= 15;i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
>线程同步
概述
是一种数据的安全机制,当多个线程同时操作一个数据的时候,为了保证数据的一致性和正确性,需要使用线程同步
同步的条件: 1)必须是多线程,必须有多并发的情况才有可能出现问题
2)多个线程可能同时操作某一个数据的时候,查询不会有影响,修改会有影响
解决方案
1>Synchronized
---方法锁
public synchronized void withdraw(double money){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
balance -= money;
}
---语句块锁
public void withdraw(double money){
System.out.println(Thread.currentThread().getName());
synchronized (this){
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
balance -= money;
}
}
2>Lock
需要手动关闭和手动开启
package thread_exercise;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* ClassName: _09_Lock
* Pacakage: thread_exercise
* Description: Lock是显示锁 需要手动开启和手动关闭
*
* @Author: 刘松泽
* @Create 2024/1/24 15:53
* @Version 1.0
*/
public class _09_Lock {
public static void main(String[] args) {
//创建一个银行卡账户对象
Account1 account1 = new Account1("10024",3000);
//创建2个线程
Thread t1 = new Thread(new Processor1(account1));
Thread t2 = new Thread(new Processor1(account1));
t1.setName("t1线程");
t2.setName("t2线程");
t1.start();
t2.start();
}
}
class Processor1 implements Runnable{
Account1 account1;
@Override
public void run() {
//此线程会从银行卡账户中取出1000元
account1.withdraw(1000);
System.out.println(Thread.currentThread().getName() + "取款完成,-->剩余" + account1.getBalance());
}
public Processor1(Account1 account1){
this.account1 = account1;
}
}
//银行卡账户实体类
class Account1{
private String id; //卡号
private double balance; //余额
//创建锁对象
Lock lock = new ReentrantLock();
public Account1() {
}
public Account1(String id, double balance) {
this.id = id;
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void withdraw(double money){
System.out.println(Thread.currentThread().getName());
//手动开启同步
lock.lock();
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
balance -= money;
//手动关闭同步
lock.unlock();
}
}