Java多线程


1.基本概念


高并发和高并行 高并行:同一时刻,多个指令在多个cpu同时执行 高并发 :同一时刻,多个指令在单个cpu上交替执行

进程和线程 进程:正在运行的程序 线程:进程中单个的顺序控制流,是一条执行路径

主线程和其他线程 主线程:进程中只有一条线程的,这个线程叫主线程 其他线程:进程中除了主线程的线程

2.实现多线程的方式


2.1创建类继承Thread类,重写run方法

public class AThread extends Thread{ @Override public void run() { System.out.println("AThread线程开启了"+Thread.currentThread().getName()); } }

publicclassDemo{
    publicstaticvoidmain(String[] args){
        AThread at = new AThread();
        at.start();
        AThread at1 = new AThread();
        at1.start();
        new AThread().start();

    }
}

2.2创建接口实现Runnable接口,实现run方法

public class ARunable implements Runnable { @Override public void run() { System.out.println("ARunnable线程开启了"+Thread.currentThread().getName()); } }

publicclassDemo{
    publicstaticvoidmain(String[] args){
        new Thread(new ARunable()).start();
        new Thread(new ARunable()).start();
        new Thread(() -> System.out.println("线程开启了"+Thread.currentThread().getName())).start();
    }
}

2.3创建接口实现Callable接口,实现call方法(优先级最低)

public class ACallable implements Callable<String> {

@Override
public String call() throws Exception {
    System.out.println("线程开启了"+Thread.currentThread().getName());
    return "线程结束了";
}

}

publicclassDemo{
    publicstaticvoidmain(String[] args)throws ExecutionException, InterruptedException {
        ACallable ac = new ACallable();
        FutureTask<String > ft = new FutureTask<>(ac);
        Thread tr =new Thread(ft);
        tr.start();
        String s = ft.get();
        System.out.println(s);

    }
}

3.线程相关api


//1.设置线程的名称(2个)(setName())publicclassThreadGet{
    publicstaticvoidmain(String[] args){
        Thread t =new Thread();
        t.setName("线程1");

    }
}
//2.获取线程名称(getName())publicclassThreadGet{
    publicstaticvoidmain(String[] args){
        Thread t =new Thread();
        t.getName();

    }
}

//3.获取当前的线程(Thread.currentThread().getName())publicclassARunableimplementsRunnable{
   @Overridepublicvoidrun(){
       System.out.println(Thread.currentThread().getName());
    }
}

//4.线程休眠(单位是毫秒)publicclassAThreadextendsThread{
    @Overridepublicvoidrun(){
        System.out.println("线程启动了");
    }
}

publicclassDemo{
    publicstaticvoidmain(String[] args){
        AThread at = new AThread();
        at.start();
        AThread at1 = new AThread();
        at1.start();
        new AThread().start();

    }
}



//5.设置当前线程的优先级(1-10),默认是5,10的优先级最高//6.设置线程为守护线程(最后一个非守护线程结束后,守护线程也会结束)

4.线程安全问题


结论:多线程同时操作类中的全局成员变量时一定会导致线程安全问题

4.1多窗口卖票

问题代码

publicclassTicketimplementsRunnable{
    //票的数量/*	问题代码
     *	ticket全局成员变量可能被多个线程同时访问,所以一定会由线程安全问题
     */privateint ticket = 100;
    privatelong startTime;
    @Overridepublicvoidrun(){
        while (true) {
            if (ticket <= 0) {
                //卖完了long endTime = System.currentTimeMillis();
                System.out.println(endTime - startTime);
                break;
            } else {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ticket--;
                System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
            }
        }
    }
}

重复票,负数票出现原因

重复票:多个线程依次执行完负数票:多个线程同时进入执行

5.如何解决线程安全问题


5.1同步代码块

public class Ticket extends Thread {
    privateint ticket = 100;

    @Override
    public void run() {
        while (true) {
            synchronized (String.class) {
                if (ticket<=0){
                    break;
                }else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(Thread.currentThread().getName()+"再卖票,还剩下"+ticket+"张票");
                }
            }
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        Ticket t = newTicket();
        Thread t1 = newThread(t);
        Thread t2 = newThread(t);
        Thread t3 = newThread(t);
        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

        t1.start();
        t2.start();
        t3.start();
    }
}

5.2同步方法

publicclassTicketDemo3extendsThread{
    privateint ticket = 100;

    @Overridepublicvoidrun(){
        while (true) {
            boolean b = synchronizedMethod();
            if (b) {
                break;
            }

        }
    }

    publicsynchronizedbooleansynchronizedMethod(){
        if (ticket == 0) {
            returntrue;

        } else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket--;
            System.out.println(Thread.currentThread().getName() + "再卖票,还剩下" + ticket + "张票");
            returnfalse;
        }
    }
}

5.3同步代码块和同步方法的所各自特点

1.同步代码可以锁住指定代码,同步方法可以锁住方法里面的所有代码2.同步代码块可以指定所锁对象,同步方法不能指定所对象

5.4自己创建锁来进行管理(ReentrantLock)

publicclassTcketDemo4extendsThread{
    privateint ticket = 100;
    private ReentrantLock rt = new ReentrantLock();

    @Overridepublicvoidrun(){
        while (true) {
            rt.lock();
            if (ticket <= 0) {
                break;
            } else {

                try {
                    Thread.sleep(100);
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "再卖票,还剩下" + ticket + "张票");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    rt.unlock();
                }
            }
        }
    }
}

publicclassDemo4{
    publicstaticvoidmain(String[] args){
        TcketDemo4 t = new TcketDemo4();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }
}

6.阻塞队列


6.1生产者消费者模型(理解)

多线程01

1.基本概念

高并发和高并行 高并行:同一时刻,多个指令在多个cpu同时执行 高并发:同一时刻,多个指令在单个cpu上交替执行

进程和线程 进程:正在运行的程序 线程:进程中单个的顺序控制流,是一条执行路径

主线程和其他线程 主线程:进程中只有一条线程的,这个线程叫主线程 其他线程:进程中除了主线程的线程

2.实现多线程的方式

2.1创建类继承Thread类,重写run方法

public class AThread extends Thread{ @Override public void run() { System.out.println("AThread线程开启了"+Thread.currentThread().getName()); } }

public class Demo {

public static void main(String[] args) {

AThread at = new AThread();

at.start();

AThread at1 = new AThread();

at1.start();

new AThread().start();

}

}

2.2创建接口实现Runnable接口,实现run方法

public class ARunable implements Runnable { @Override public void run() { System.out.println("ARunnable线程开启了"+Thread.currentThread().getName()); } }

public class Demo {

public static void main(String[] args) {

new Thread(new ARunable()).start();

new Thread(new ARunable()).start();

new Thread(() -> System.out.println("线程开启了"+Thread.currentThread().getName())).start();

}

}

2.3创建接口实现Callable接口,实现call方法(优先级最低)

public class ACallable implements Callable<String> {

@Override

public String call() throws Exception {

System.out.println("线程开启了"+Thread.currentThread().getName());

return "线程结束了";

}

}

public class Demo {

public static void main(String[] args) throws ExecutionException, InterruptedException {

ACallable ac = new ACallable();

FutureTask<String > ft = new FutureTask<>(ac);

Thread tr =new Thread(ft);

tr.start();

String s = ft.get();

System.out.println(s);

}

}

3.线程相关api

//1.设置线程的名称(2个)(setName())

public class ThreadGet {

public static void main(String[] args) {

Thread t =new Thread();

t.setName("线程1");

}

}

//2.获取线程名称(getName())

public class ThreadGet {

public static void main(String[] args) {

Thread t =new Thread();

t.getName();

}

}

//3.获取当前的线程(Thread.currentThread().getName())

public class ARunable implements Runnable{

@Override

public void run() {

System.out.println(Thread.currentThread().getName());

}

}

//4.线程休眠(单位是毫秒)

public class AThread extends Thread{

@Override

public void run() {

System.out.println("线程启动了");

}

}

public class Demo {

public static void main(String[] args) {

AThread at = new AThread();

at.start();

AThread at1 = new AThread();

at1.start();

new AThread().start();

}

}

//5.设置当前线程的优先级(1-10),默认是5,10的优先级最高

//6.设置线程为守护线程(最后一个非守护线程结束后,守护线程也会结束)

4.线程安全问题

结论:多线程同时操作类中的全局成员变量时一定会导致线程安全问题

4.1多窗口卖票

问题代码

public class Ticket implements Runnable {

//票的数量

/*问题代码

*ticket全局成员变量可能被多个线程同时访问,所以一定会由线程安全问题

*/

private int ticket = 100;

private long startTime;

@Override

public void run() {

while (true) {

if (ticket <= 0) {

//卖完了

long endTime = System.currentTimeMillis();

System.out.println(endTime - startTime);

break;

} else {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");

}

}

}

}

重复票,负数票出现原因

重复票:多个线程依次执行完

负数票:多个线程同时进入执行

5.如何解决线程安全问题

5.1同步代码块

public class Ticket extends Thread {

private int ticket = 100;

@Override

public void run() {

while (true) {

synchronized (String.class) {

if (ticket<=0){

break;

}else {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName()+"再卖票,还剩下"+ticket+"张票");

}

}

}

}

}

public class Demo {

public static void main(String[] args) {

Ticket t = new Ticket();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

Thread t3 = new Thread(t);

t1.setName("窗口一");

t2.setName("窗口二");

t3.setName("窗口三");

t1.start();

t2.start();

t3.start();

}

}

5.2同步方法

public class TicketDemo3 extends Thread {

private int ticket = 100;

@Override

public void run() {

while (true) {

boolean b = synchronizedMethod();

if (b) {

break;

}

}

}

public synchronized boolean synchronizedMethod() {

if (ticket == 0) {

return true;

} else {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName() + "再卖票,还剩下" + ticket + "张票");

return false;

}

}

}

5.3同步代码块和同步方法的所各自特点

1.同步代码可以锁住指定代码,同步方法可以锁住方法里面的所有代码

2.同步代码块可以指定所锁对象,同步方法不能指定所对象

5.4自己创建锁来进行管理(ReentrantLock)

public class TcketDemo4 extends Thread {

private int ticket = 100;

private ReentrantLock rt = new ReentrantLock();

@Override

public void run() {

while (true) {

rt.lock();

if (ticket <= 0) {

break;

} else {

try {

Thread.sleep(100);

ticket--;

System.out.println(Thread.currentThread().getName() + "再卖票,还剩下" + ticket + "张票");

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

rt.unlock();

}

}

}

}

}

public class Demo4 {

public static void main(String[] args) {

TcketDemo4 t = new TcketDemo4();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

Thread t3 = new Thread(t);

t1.start();

t2.start();

t3.start();

}

}

6.阻塞队列

6.1生产者消费者模型(理解)

生产者消费者模型

6.2线程的等待唤醒机制

线程的等待和唤醒必须借助于同一把锁

锁对象.class.wait() 让当前的线程等着

锁对象.class.notify() 让锁对象的等着的线程苏醒

但是必须是同一个锁对象。

6.3阻塞队列的使用

阻塞队列

常见BlockingQueue

ArrayBlockingQueue: 底层是数组,有界

LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值

阻塞队列使用步骤

初始化

//阻塞队列初始化

ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

生产者添加数据到队列

queue.put("汉堡包");

消费者从队列中获取数据

注意,取不到数据就会挂在哪里等,什么时候取到什么时候执行

String data = queue.take()

6.2线程的等待唤醒机制

线程的等待和唤醒必须借助于同一把锁

锁对象.class.wait() 让当前的线程等着锁对象.class.notify() 让锁对象的等着的线程苏醒但是必须是同一个锁对象。

6.3阻塞队列的使用

阻塞队列

  • 常见BlockingQueue

  • ArrayBlockingQueue: 底层是数组,有界

  • LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值

阻塞队列使用步骤

初始化

//阻塞队列初始化
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

生产者添加数据到队列

queue.put("汉堡包");

消费者从队列中获取数据

注意,取不到数据就会挂在哪里等,什么时候取到什么时候执行

String data = queue.take()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QD_IT伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值