多线程开发:并发编程 多线程程序的好处:提高程序的效率 多线程程序如何开发? 方式1 : Thread类(java语言提供的现成的线程类) 1. 创建一个子类,继承Thread类 (创建的子类:也是线程类) 2. 在子类中,编写让线程帮助完成的任务(任务代码) //重写Thread类中的run方法(线程任务) 3. 启动线程 弊端:类只能单一继承 public class 子类 extends Father { //问题:还能在继承Threa类吗? } 方式2 :Runnable接口 (接口可以多实现,而且允许子类在继承其他父类) 【推荐 : 灵活度高】 1. 创建一个子类, 实现Runnable接口 2. 在子类中,重写Runnable接口中的方法:run (线程任务方法) 3. 创建Thread类对象, 并把实现了Runnable接口的子类对象,作为参数传递给Thread类对象 new Thread( Runnable类型的对象 ) 4. 启动线程 多线程程序的开发方式: 方式1 :Thread 1. 创建子类,继承Thread类 (不能在继承其他父类了) 2. 子类中重写run方法 (线程任务) 2. 创建子类对象,调用start方法(启动线程) //线程任务、线程功能 全部都在Thread子类中 方式2 : Runnable 1. 创建子类 ,实现Runnable (可以继承其他父类) 2. 重写run方法 (线程任务) 3. 创建Thread类对象, 并指定要执行的线程任务(Runnable实现类对象作为参数,传递到Thread类的构造方法中) 4. Thread类对象.start() (启动线程) //线程任务 : Runnable接口实现类 //线程功能 : Thread类 推荐使用Runnable接口的方式,好处:解耦 接口的作用: 1. 制定规则 2. 可以降低耦合 (耦合:紧密连接的程度) //程序都是要求低耦合 并发编程 -- 什么是并发编程 在一个程序中开启多个线程,让多个线程执行相同的任务,从而提高程序执行效率。 -- 并发编程解决程序中的什么问题 提高程序的运行效率、提高使用者体验 -- 并发编程怎么写 1、Thread类 2、Runnable接口 在Java程序中运行的线程都有属于自己的名字。 例:main方法,就代表主线程(线程名字:main) 新线程名字: Thread-0 、Thread-1、............ String getName() //获取线程的名字 void setName(String name) //给线程设置一个名字 static Thread currentThread() //获取当前正在运行的线程对象 static void sleep(long 毫秒) //让当前运行的线程休息(单位 :毫秒) void join() //挂起其他线程,仅当前线程运行 发生线程安全问题的原因: 多个线程对同一个数据,进行读写操作,造成数据错乱 线程安全问题的解决思想: 把多个线程操作的共享数据,存放到一个安全的环境中 java语言基于线程安全问题,提供了:同步机制 同步: 1. 同步代码块 2. 同步方法 3. Lock锁 同步方法: 修饰符号 synchronized 返回值类型 方法名(参数列表){ } 同步方法也有对象锁: 1. this锁 (当前对象锁) 2. 类名.class (静态方法上的对象锁)
并行和并发
并行:在同一时刻,有多个任务在多个cpu上同时去进行
并发:在同一时刻,有多个任务在一个cpu上去执行
进程简单地说就是在多个任务操作系统中,每个独立执行的程序
线程是程序进行地基本执行单元
多线程是指从软件或者是硬件上实现的多个线程地并发执行地技术
具有多线程能力地计算机因有硬件的支持而能够在同一时间执行多个线程,提升了性能
例如迅雷就是一种多线程的下载方式
创建一个子类,继承Thread类 (创建的子类:也是线程类)
重写这个Thread的run方法
启动线程
cpu就会在主线程和新线程中高速交换执行
package thread;
/**
* @author xiaowang
* @creat 2024/6/14 18:52
* @Description Java Lotus
*/
public class ThreadDemo1 {
public static void main(String[] args) {
System.out.println("进入main方法进行执行");
MyThread myThread=new MyThread();
myThread.start();
for (int i = 0; i <1000 ; i++) {
System.out.println(i);
}
}
}
package thread;
/**
* @author xiaowang
* @creat 2024/6/14 18:52
* @Description Java Lotus
*/
public class MyThread extends Thread{
//需要当前线程去完成一个任务
@Override
public void run(){
System.out.println("新的线程开始执行");
for (int i = 100; i <2000 ; i++) {
System.out.println("新线程"+i);
}
}
}
线程的使用:Runnable接口
类只能单一继承
我们现在已经继承类一个父类了,如果还是想再去继承一个类的时候,我们是无法做到的,所以,这个就是runnable接口的引入的问题场景
接口是可以多实现的,并且还可以让子类去继承其他的类
推荐,他的灵活度特别高
创建一个子类,实现一个runnable接口
在子类中,重写这个runnable接口中的方法run (线程任务方法)
创建Thread类对象,并把实现了runnable接口的子类对象
作为参数传递给Thread类对象
package thread.project2;
/**
* @author xiaowang
* @creat 2024/6/14 19:11
* @Description Java Lotus
*/
public class ThreadDemo {
public static void main(String[] args) {
System.out.println("进入到主线程中执行方法");
MyTask task =new MyTask();
Thread thread = new Thread(task);
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
}
package thread.project2;
/**
* @author xiaowang
* @creat 2024/6/14 19:10
* @Description Java Lotus
*/
public class MyTask implements Runnable{
@Override
public void run() {
System.out.println("新线程方法开始执行");
for (int i = 100; i <200 ; i++) {
System.out.println("新线程"+i);
}
}
}
第一种:方式一,实现多线程
Thread
创建一个子类,继承Thread类
子类中重写run方法
创建子类对象
方式2:Runnable
创建一个子类,实现runnable方法,是一个接口,是可以去继承其他父类的
创建一个Thread类对象,并且指定去执行的线程任务
(Runnable实现对象作为参数,传递到Thread类的构造方法)
回顾:线程的使用
并发编程
--什么是并发编程呢
在一个程序中开启多个线程,让多个线程执行相同的一个任务,从而提高的程序执行效率
--并发编程解决了程序中的什么问题
提高了效率和使用者的体验
并发编程怎么写
package thread.project3;
/**
* @author xiaowang
* @creat 2024/6/14 19:26
* @Description Java Lotus
*/
public class TheadTask1 extends Thread{
@Override
public void run(){
for (int i = 100; i <200 ; i++) {
System.out.println(i);
}
}
}
package thread.project3;
/**
* @author xiaowang
* @creat 2024/6/14 19:27
* @Description Java Lotus
*/
public class Test1 {
public static void main(String[] args) {
TheadTask1 task1 =new TheadTask1();
task1.start();
for (int i = 100; i <200 ; i++) {
System.out.println("main方法"+i);
}
}
}
package thread.project3;
/**
* @author xiaowang
* @creat 2024/6/14 19:30
* @Description Java Lotus
*/
public class ThreadTask2 implements Runnable{
@Override
public void run() {
for (int i = 100; i <200 ; i++) {
System.out.println(i);
}
}
}
package thread.project3;
/**
* @author xiaowang
* @creat 2024/6/14 19:30
* @Description Java Lotus
*/
public class Test2 {
public static void main(String[] args) {
Thread thread = new Thread(()->{
for (int i = 100; i <200 ; i++) {
System.out.println(i);
}
});
thread.start();
for (int i = 100; i <200 ; i++) {
System.out.println("main方法"+i);
}
}
}
线程中的常用方法
线程安全问题
多个线程对同一个数据重写操作所产生的错乱,对同一个数据进入读和写
程序是不可以去控制cpu的
线程安全问题解决思路
多线程对同一个数据进行读写操作
同步代码块
1.同步代码块:
2.同步方法:
3.lock锁
使用同步锁以避免在该程序完成操作之前,被其他线程的调用,从而保证该变量额唯一性和准确性
synchronized(同步锁)
多个线程要去使用同一把锁
package com.itheima.thread.security.demo2;
//线程任务类
public class Ticket implements Runnable {
//成员变量(电影票数)
private int ticketCount = 100;//有100张电影票
//锁对象(任意类型对象)
Object lock = new Object();
@Override
public void run() {
//模拟卖票
while (true) {
//使用同步代码块,解决线程安全问题
synchronized (lock) {
if (ticketCount <= 0) {
break;
}
if (ticketCount > 0) {
// 模拟出票的时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 出售票号:" + ticketCount);
ticketCount--;
}
}
}
}
}
package com.itheima.thread.security.demo3;
//线程任务类
public class Ticket implements Runnable {
//成员变量(电影票数)
private int ticketCount = 100;//有100张电影票
@Override
public void run() {
//模拟卖票
while (true) {
if (ticketCount <= 0) {
break;
}
method();
}
}
//同步方法 (方法中所有的代码都是同步代码)
private synchronized void method() {
if (ticketCount > 0) {
// 模拟出票的时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 出售票号:" + ticketCount);
ticketCount--;
}
}
}
package com.itheima.thread.security.demo4;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//线程任务类
public class Ticket implements Runnable {
//成员变量(电影票数)
private int ticketCount = 100;//有100张电影票
//Lock锁对象
Lock l = new ReentrantLock();
@Override
public void run() {
//模拟卖票
while (true) {
//使用Lock锁解决线程安全问题
//获取锁
l.lock();
if (ticketCount <= 0) {
break;
}
if (ticketCount > 0) {
// 模拟出票的时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 出售票号:" + ticketCount);
ticketCount--;
}
//释放锁
l.unlock();
}
}
}
lock锁
kock和unlock两个方法
线程的死锁
理解线程死锁的条件
互相使用双方的两个锁
死锁是在程序中没办法通过程序去解决的
在程序两个线程中不用交叉使用锁
同步代码块的锁进行了嵌套的使用,就大概率会产生死锁
不要去使用嵌套锁
线程的6种状态
线程的生命周期
new- 创建线程对象
runnable - start方法
blocked- 无法获得锁对象
waiting - wait方法
timed——waiting sleep方法
terminated 全部代码运行完毕
线程状态
标签:总结,Runnable,run,Thread,子类,线程,全面,public From: https://blog.csdn.net/Darling912/article/details/139688169