Java基础——多线程

一、基本概念:程序、进程、线程

程序:一段静态代码

进程:一个正在执行的程序

线程:一个程序内部的一条执行路径(一大段代码分成一份或几份代码执行,它是其中一份)

在这里插入图片描述

并行:多线程执行多个任务,每个任务之间独立,互不干扰

并发:多线程执行一个任务

二、线程的创建和使用

线程默认优先级

MAX_PRIORITY:10

MIN _PRIORITY:1

NORM_PRIORITY:5

涉及的方法

getPriority() :返回线程优先值

setPriority(intnewPriority) :改变线程的优先级

Thread类相关方法

void start(): 启动线程,并执行对象的run()方法

run(): 线程在被调度时执行的操作

String getName(): 返回线程的名称

void setName(String name):设置该线程名称

static Thread currentThread(): 返回当前线程。在Thread子类中就是this,通常用于主线程和Runnable实现类

static void yield():线程让步

暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程

若队列中没有同优先级的线程,忽略此方法

join():当某个程序执行流中调用其他线程的join() 方法时,调用线程将被阻塞,直到join() 方法加入的join 线程执行完为止

低优先级的线程也可以获得执行

static void sleep(long millis):(指定时间:毫秒)令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队,进入阻塞状态。

抛出InterruptedException异常

线程的分类

Java中的线程分为两类:一种是守护线程,一种是用户线程。

它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。

守护线程是用来服务用户线程的,通过在start()方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程。

Java垃圾回收就是一个典型的守护线程

若JVM中都是守护线程,当前JVM将退出

1.继承Thread类

public class ThreadTest01 {
    public static void main(String[] args) {
        //3.创建那个类的对象
        ThreadTest threadTest01 = new ThreadTest();
        ThreadTest threadTest02 = new ThreadTest();
        //通过调用该对象的start方法去启动线程
        threadTest01.start();
        threadTest02.start();
    }
}
//1.创建一个继承Thread类的类
class ThreadTest extends Thread {
    //2.重写Thread的run方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

2.实现Runnable接口

①一般实现

public class ThreadTest02 {
    public static void main(String[] args) {
        //3.创建那个实现Runnable接口的类的对象
        RunnableTest runnableTest = new RunnableTest();
        //4.通过Thread的类去创建一个线程
        Thread thread01 = new Thread(runnableTest);
        Thread thread02 = new Thread(runnableTest);
        //5.通过start调用线程
        thread01.start();
        thread02.start();
    }
}
//1.创建一个实现Runnable接口的类
class RunnableTest implements Runnable {
    //2.实现Runnable的run方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

②匿名内部类实现

public class ThreadTest03 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }).start();
    }
}

③lambda表达式实现

new Thread(()-> System.out.println(Thread.currentThread().getName())).start();

3.实现Callable接口(jdk5.0新增)

创建线程的方式三:实现Callable接口。 --- JDK 5.0新增
如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?
1. call()可以有返回值的。
2. call()可以抛出异常,被外面的操作捕获,获取异常的信息
3. Callable是支持泛型的
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadTest04 {
    public static void main(String[] args) {
        //3.
        CallableTest callableTest = new CallableTest();
        //4.
        FutureTask futureTask = new FutureTask(callableTest);
        //5.
        new Thread(futureTask).start();
        try {
            Object o = futureTask.get();
            System.out.println(o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
//1.
class CallableTest implements Callable {
    //2.
    @Override
    public Object call() throws Exception {
        int num = 0;
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
            num += i;
        }
        return num;
    }
}

4.线程池创建(jdk5.0新增)

创建线程的方式四:使用线程池
好处:
1.提高响应速度(减少了创建新线程的时间)
2.降低资源消耗(重复利用线程池中线程,不需要每次都创建)
3.便于线程管理
     corePoolSize:核心池的大小
     maximumPoolSize:最大线程数
     keepAliveTime:线程没有任务时最多保持多长时间后会终止
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class ThreadTest05 {
    public static void main(String[] args) {
        //2.
        ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service01 = (ThreadPoolExecutor) service;
        //3.
        service.execute(new ThreadTool01());
        service.execute(new ThreadTool02());
        //4.
        service.shutdown();
    }
}
//1.
class ThreadTool01 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
class ThreadTool02 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

三、线程的生命周期

在这里插入图片描述

四、线程的同步

问题的提出

模拟火车站售票程序,开启三个窗口售票。

public class ThreadTest06 {
    public static void main(String[] args) {
        //多核多线程的电脑,跑不出-1,0,因为第一个sleep线程醒来还没print了还没--第二个线程就print了,是真多线程在跑
        //打印同时ticket-- 和 换行ticket--从结果上看效率明显不一样,因为 打印同时ticket--永远看不到第三次打印1
        Runnable windows = new Runnable() {
            private int tickets = 100;

            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (tickets > 0) {
                        System.out.println(Thread.currentThread().getName() + ":" + tickets);
                        tickets--;
                    }else {
                        break;
                    }
                }
            }
        };
        Thread thread01 = new Thread(windows);
        Thread thread02 = new Thread(windows);
        Thread thread03 = new Thread(windows);
        thread01.start();
        thread02.start();
        thread03.start();
    }
}


线程同步的机制

让一个线程进入执行,其他不能进入执行,直到这个线程执行完

优点:解决线程安全问题

缺点:效率低

1.同步代码块(synchronized)

synchronized(同步监视器){
	//代码
}

同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。要求:多个线程必须要共用同一把锁。

保证唯一的有,任一Class对象

2.同步方法

public synchronized void show (String name){ ....}

自动释放锁的操作

1.当前线程的同步方法、同步代码块执行结束

2.当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。

3.当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束。

4.当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。

不会释放锁的操作

1.线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行

2.线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。

3.锁(Lock,jdk5.0新增)

import java.util.concurrent.locks.ReentrantLock;

public class ThreadTest07 {
    public static void main(String[] args) {
        Runnable windows = new Runnable() {
            private int tickets = 100;
            private ReentrantLock lock = new ReentrantLock();

            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lock.lock();
                    try {
                        if (tickets > 0) {
                            System.out.println(Thread.currentThread().getName() + ":" + tickets);
                            tickets--;
                        }else {
                            break;
                        }
                    } finally {
                    lock.unlock();
                    }

                }
            }
        };
        Thread thread01 = new Thread(windows);
        Thread thread02 = new Thread(windows);
        Thread thread03 = new Thread(windows);
        thread01.start();
        thread02.start();
        thread03.start();
    }
}

synchronized与lock的区别?

相同:对可以解决线程安全问题

不同:

1.synchronized自动释放锁,lock手动

2.lock只能作用代码块,synchronized代码块和方法

五、线程的通信

wait() 与notify() 和notifyAll()

wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行

调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)

notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等

notifyAll():唤醒正在排队等待资源的所有线程结束等待

问题

1.使用Runnable创建线程时,Thread类是如何调用它的run方法的?

调用构造参数时,run方法内部调用了实现Runnable类的run方法
在这里插入图片描述
在这里插入图片描述

面试题

一、sleep()和wait()方法的区别?

1.sleep的定义是在Thread类中,wait的定义是Object类中

2.wait会释放锁,sleep不会

二、请说出你所知道的线程同步的方法

1.同步代码块

2.同步方法

3.jdk5.0新增锁类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值