Java 线程基础

【韩顺平讲Java】线程 Thread Synchronized 互斥锁 进程 并行 并发 死锁等

01----线程,进程相关概念

  • 进程:进程是指运行中的程序,是程序的一次执行过程。
  • 线程:线程由进程创建,是进程的一个实体,一个进程可以有多个线程
  • 线程也可以创建线程

02----并发,并行

  • 单线程:同一时刻,只允许执行一个线程
  • 多线程:同一时刻,可以执行多个线程
  • 并发:同一时刻,多个任务交替执行,造成一种“貌似同时”的错觉,如单核CPU实现多任务
  • 并行:同一时刻,多个任务同时执行

03----线程的创建方式

  1. 继承Thread
  2. 实现Runnable接口
  3. 启动多线程必须调用start()方法
//方式一:
public class ThreadTest01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.start();	//启动多线程必须调用start()方法
    }
}

class Cat extends Thread{
    @Override
    public void run() {
        super.run();	//这里根据要求重写方法体
    }
}

// 方式二:
public class RunnableTest01 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        new Thread(dog).start();	//代理模式:静态代理
    }
}

class Dog implements Runnable{
    @Override
    public void run() {

    }
}

05----为什么调用start()方法?

  • start()调用本地方法(native)方法start0(),真正实现多线程的是start0()方法
  • start()调用start0()方法后,该线程并不一定会立即执行,只是将线程变成了可运行状态,具体什么时候执行取决于CPU,由CPU统一调度

08----多线程售票问题(多个线程操作同一个对象)

public class SellTickets {
    public static void main(String[] args) {

        Tickets tickets1 = new Tickets();
        Tickets tickets2 = new Tickets();
        Tickets tickets3 = new Tickets();
        tickets1.start();
        tickets2.start();
        tickets3.start();
    }
}

class Tickets extends Thread{
    int numTickets = 20;

    @Override
    public void run() {
        while (true){
            if (numTickets <= 0){
                break;
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+ "卖出了一张票,剩余:" + (--numTickets));
        }
    }
}

10----线程的方法

  1. interrupt:中断,不是退出
  2. sleep:休眠
  3. start:
  4. yield:礼让,不一定成功
  5. join:插队,插入成功则一直执行到完毕

13----守护线程

  1. 用户线程:也叫工作线程,当线程的任务执行完或者以通知方式结束
  2. 守护线程:一般是为工作线程服务的,当所有用户线程结束,守护线程自动结束,如垃圾回收机制
MyDaemonThread t1 = new MyDaemonThread;	//Daemon:守护

t1.setDaemon(true);
t1.start();

14----线程的7大状态

  1. NEW:新建
  2. RUNNABLE:可运行
    • Ready:就绪
    • Running:运行
  3. BLOCKED:阻塞
  4. WAITING:等待
  5. TIMED_WAITING:超时等待,如sleep
  6. TERMINATED :终止

15----线程的同步

互斥锁:保证数据的完整性。

synchronized:1. 同步方法, 2. 同步代码块

互斥锁注意事项:
  • // 同步方法(非静态)的锁可以是this,也可以是其他对象(要求是同一个对象);

  • // 同步方法(静态的)的锁只能是当前类本身;

  • 多个线程的锁必须是同一个。

//------------------同步方法------------------------
/*
 * 多个线程同时操作一个对象
 * 买火车票的例子
 *
 * 发现问题:多个线程操作一个对象,线程不安全,数据紊乱
 * */
public class SellTickets03 implements Runnable{

    int ticketNum = 10;
    boolean loop = true;

    @Override
    public void run() {
        while (loop) {
            sell();
        }
    }

    public synchronized void sell(){
        if (ticketNum<=0){
            loop = false;
            return;
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 拿到了第 " + ticketNum-- + " 票");
    }

    public static void main(String[] args) {

        SellTickets03 ticket = new SellTickets03();

        new Thread(ticket).start();
        new Thread(ticket).start();
        new Thread(ticket).start();
    }
}


public class SellTickets02 {
    public static void main(String[] args) {

        Tickets02 tickets1 = new Tickets02();

        new Thread(tickets1).start();
        new Thread(tickets1).start();
        new Thread(tickets1).start();

    }
}

//------------------同步代码块------------------------
class Tickets02 implements Runnable{
    private int numTickets = 10;
    boolean loop = true;

    public void sell(){
        synchronized (this){    // 同步方法(非静态)的锁可以是this,也可以是其他对象(要求是同一个对象);
            // 同步方法(静态的)的锁只能是当前类本身;
            if (numTickets <= 0) {
                loop = false;
                return;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余:" + --numTickets);
        }
    }
    @Override
    public void run() {
        while (loop){
            sell();
        }
    }
}

17----线程死锁

多个线程互相抱着对方需要的资源,然后形成僵持

某一个同步块同时拥有”两个以上对象的锁“时,就有可能发生死锁问题,如下:

if(...){
    synchronized (lock1){
        .............
            synchronized (lock2){
            ..........
        }
    }
}else{
    synchronized (lock2){
        .............
            synchronized (lock1){
            ..........
        }
    }    
}

18----释放锁

  • 下面情况会释放锁
    1. 当前线程的同步方法,同步代码块执行结束
    2. 当前线程的同步方法,同步代码块遇到break,return
    3. 当前线程在同步方法,同步代码块中出现了未处理的error或exception,导致异常结束
    4. 当前线程在同步方法,同步代码块中执行了线程对象的wait()方法,当前线程暂停,并释放锁
  • 下面情况不会释放锁
    1. 线程执行同步方法,同步代码块时,程序掉哦用了sleep()方法,yield()方法暂停当前线程的执行,不会释放锁
    2. 线程执行同步代码块,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁

19----作业

import java.util.Locale;
import java.util.Scanner;

public class Homework01 {
    /*
    * 在main中启动两个线程
    * 线程a循环随机打印100以内的整数
    * 直到线程b从键盘读入“Q”停止  (因此,b得有a的对象)
    * */

    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);
        a.start();
        b.start();

    }
}

class A extends Thread{

    boolean loop = true;

    @Override
    public void run() {
        while (loop){
            System.out.println((int)(Math.random()*100+1));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程a已推出");
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

class B extends Thread{
    A a;
    Scanner scanner = new Scanner(System.in);

    public B(A a) {
        this.a = a;
    }

    @Override
    public void run() {
        //System.out.println("线程b已开启,输入Q停止线性a:");
        while (true){
            System.out.println("线程b已开启,输入Q停止线性a:");

            if (scanner.next().toUpperCase().charAt(0) == 'Q'){
                a.setLoop(false);
                System.out.println("线程b已退出");
                break;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

作业二:

public class Homework02 {
    /*
    * 有两个用户在同一个卡上取钱(总额:1w)
    * 每次都取1000,当余额不足时,就不能再取款
    * 线程同步问题
    * 多个线程共享资源,优先选取Runnable方式
    * */

    public static void main(String[] args) {

        T t = new T();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t1.setName("Xiaoming");
        t2.setName("Dazhuang");
        t1.start();
        t2.start();
    }
}

class T implements Runnable{

    private int money = 10000;

    @Override
    public void run() {
        while (true) {
            synchronized (this){	// 加锁
                if (money <= 0) {
                    break;
                }
                money = money - 1000;
                System.out.println(Thread.currentThread().getName() + "取走了1000元,现在余额为:" + money);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值