1什么是进程?
狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
2.什么是线程
线程是一个独立的执行路径,它是操作系统能够进行运算调度的最小单位。一个进程可以拥有多个线程,这些线程可以并发执行不同的任务。
2.1什么是多线程
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理” 。
2.2线程和进程的区别
进程是操作系统中的一个执行单元,它拥有独立的内存空间和系统资源;线程是进程中的一个执行单元,它与同一进程中的其他线程共享内存空间和系统资源。
3.JAVA中如何创建多线程
继承Thread 类 ,重写run方法
MyThread
public class MyThread extends Thread{
/*第一种方法,继承Thread 重写run方法
* 线程启动时,会调用run方法中的代码*/
@Override
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println("run线程"+i);
}
}
}
测试类
public class Test {
public static void main(String[] args) {
//创建一个线程对象
MyThread myThread = new MyThread();
//start开启线程会自动调用线程的方法,来执行线程任务
myThread.start();
for (int i = 0; i < 20; i++) {
System.out.println("main线程"+i);
}
}
}
3.1获取和设置线程的名称
this.getName 获取当前线程的名称
Thread.currentThread .getName 也能获取当前线程名称(该方法可以在任意位置获取 )
MyThread
public class MyThread extends Thread{
/*第一种方法,继承Thread 重写run方法
* 线程启动时,会调用run方法中的代码*/
@Override
public void run(){
for (int i = 0; i < 20; i++) {
//this.getName 获取当前线程的名称 只能用在Thread子类下
//System.out.println("run线程"+i);
System.out.println(this.getName()+"线程"+i);
}
}
}
@Override
public void run(){
for (int i = 0; i < 20; i++) {
//this.getName 获取当前线程的名称 只能用在Thread子类下
//System.out.println("run线程"+i);
// System.out.println(this.getName()+"线程"+i);
System.out.println(Thread.currentThread().getName()+"线程"+i);
}
}
}
测试
public class Test {
public static void main(String[] args) {
//创建一个线程对象
MyThread myThread = new MyThread();
MyThread myThread1 = new MyThread();
//start开启线程会自动调用线程的方法,来执行线程任务
myThread.start();
myThread1.start();
}
}
setName 可为线程对象设置名称
public class Test {
public static void main(String[] args) {
//创建一个线程对象
MyThread myThread = new MyThread();
myThread.setName("线程A");//为线程对象设置名称
MyThread myThread1 = new MyThread();
myThread1.setName("线程B");
//start开启线程会自动调用线程的方法,来执行线程任务
myThread.start();
myThread1.start();
}
}
3.2案例(买票 会出现了超卖和重卖: 这是因为线程安全问题。----解决线程安全问题。 )
public class MyTicketTask extends Thread{
private static int ticket=100;
//卖100张票
@Override
public void run(){
while (ticket>0){
ticket--;
System.out.println(Thread.currentThread().getName()+"卖了1张票:剩余:"+ticket+"张");
}
}
}
public class Test {
public static void main(String[] args) {
MyTicketTask myTicketTask = new MyTicketTask();
myTicketTask.setName("1窗口");
MyTicketTask myTicketTask1 = new MyTicketTask();
myTicketTask1.setName("2窗口");
MyTicketTask myTicketTask2 = new MyTicketTask();
myTicketTask2.setName("3窗口");
MyTicketTask myTicketTask3 = new MyTicketTask();
myTicketTask3.setName("4窗口");
myTicketTask.start();
myTicketTask1.start();
myTicketTask2.start();
myTicketTask3.start();
}
}
会出现线程安全问题
3.3 实现Runnable接口
public class My implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"==="+i
);
}
}
}
public class Test {
public static void main(String[] args) {
//创建任务对象
My my = new My();
//Thread是线程对象
Thread thread = new Thread(my);
//开启线程
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("main==="+i);
}
}
}
- 实现接口Runnable具有多线程能力。
- 启动线程: 传入目标对象 + Thread对象.start () 。
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
4. Thread线程类中常用的方法
start():启动线程,使其进入可运行状态。
- run():线程的主体方法,包含线程的实际执行逻辑。
- join():等待线程终止。
- sleep(long millis):使线程休眠指定的时间。
- interrupt():中断线程。
- isAlive():检查线程是否处于活动状态。
- setName(String name):设置线程的名称。
- getName():获取线程的名称。
- setPriority(int priority):设置线程的优先级。
- getPriority():获取线程的优先级
- 11.yield() 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
- 线程对象.setDaemon(true);设置为守护线程
5.线程安全问题
5.1什么是线程安全问题?
指多个线程在执行同一段代码的时候采用加锁机制, 使每次的执行结果和单线程执行结果一样的, 不存在执行程序时出现意外结果
线程不安全
线程不安全是指不提供加锁机制保护, 有可能出现多个线程先后更改数据造成所得到的数据是脏数据
5.2如何解决线程不安全问题
3.如何解决线程安全问题
- 使用同步机制, 使得在同一时间只能有一个线程修改共享数据
- 消除共享数据, 即多个线程数据不共享或者共享的数据不被做修改 如果使用成员变量, 对成员变量不进行修改
(同步代码块 同步方法 Notiy锁)- synchronized
自动锁:
public class TicketTask implements Runnable{
private static int ticket =100;
//创建手动锁对象
private Lock l = new ReentrantLock();
public void run() {
while (true){
synchronized (this){//自动上锁和释放锁。
if(ticket>0){
ticket--;
System.out.println(Thread.currentThread().getName()+"卖了1张票;剩余:"+ticket+"张");
}else {
break;
}
}
手动锁:
public class TicketTask implements Runnable{
private static int ticket =100;
//创建手动锁对象
private Lock l = new ReentrantLock();
public void run() {
while (true){
l.lock();//手动上锁
if (ticket > 0) {
ticket--;
System.out.println(Thread.currentThread().getName() + "卖了一张票;剩余:" + ticket + "张");
} else {
break;
}
l.unlock();//手动释放锁
}
}
}