Java多线程

目录

Thread

线程定义

定义方法1

定义方法2:

建议使用定义2,实现Runnable的好处:多个线程跑同一个对象。直接继承Thread,一个对象只能被继承Thread的子类使用。

龟兔赛跑

lamda表达式

线程状态

停止线程

线程休眠

线程礼让

线程强制执行Join

线程状态

线程优先级

守护线程

线程同步机制(锁)

同步方法

死锁

Lock锁(显式)

线程协作(生产消费)

线程池


Thread

线程定义

使用同一对象生成的线程共享对象内资源。

定义方法1

自定义线程类需要继承Thread类并重写run()方法

public class SonThread extends Thread{
    public void run(){
        //线程体
    }
    public static void main(String[]args){
        //创建线程对象并开启线程
        SonThread s = new SonThread();
        s.start();
    }
}

定义方法2:

实现Runnable接口,实现run()方法,创建线程对象

public class Run1 implements Runnable{
	public void run(){
	
	}
}
public class Main{
	public static void main(String[]args){
		Thread thread1 = new Thread(new Run1());
	}
}

建议使用定义2,实现Runnable的好处:多个线程跑同一个对象。直接继承Thread,一个对象只能被继承Thread的子类使用。

例子:

//多线程操作同一个对象  买火车票的例子
public class TestThreadDemo01 implements Runnable{
    //这个类可以看成一个票站,每个线程看成买票的。
    private int ticketNums ;  //票的数量

    public TestThreadDemo01(int ticketNums) {
        this.ticketNums = ticketNums;
    }
    @Override
    public void run(){
        while(true){
            if(ticketNum <=0){
                break;
            }
            try {
                Thread.sleep(200);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+" 拿到了第 "+ ticketNum -- + "张票");
        }
    }

    public static void main(String[] args) {
        TestThreadDemo01 testThreadDemo01 = new TestThreadDemo01(10);  //生成一个拥有10张票的票站
        new Thread(testThreadDemo01,"张三").start();   //买票
        new Thread(testThreadDemo01,"李四").start();
        new Thread(testThreadDemo01,"王五").start();
    }
}

龟兔赛跑

public class Race implements Runnable {
    //该类就像一条赛道

    //赛道长度
    private int length;

    //是否跑完
    private  static boolean flag = false;


    public Race(int length) {
        this.length = length;
    }

    private  static String  winner; //注意得static 不然会有两个winner
    @Override
    public void run() {
        int i;
        for (i =1; i <=length;i++){
            //是否结束
            if(flag == true)
                break;

            //兔子快到终点时睡觉
            if(i == 80 && Thread.currentThread().getName() == "兔子") {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " 跑了 " + i + " 米");
        }
        //结束

        if(i == 101){
            flag = true;
            winner = Thread.currentThread().getName();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("winner: " + winner);
        }

    }

    public static void main(String[] args) {
        Race race = new Race(100); //生成100m的赛道
        new Thread(race,"兔子").start();  //兔子乌龟上赛道
        new Thread(race,"乌龟").start();
    }
}

lamda表达式

任何接口,如果是只包含唯一一个抽象方法,那么它就是函数式接口。

函数式接口可以通过lamda表达式来创建接口。

lamda表达式是匿名内部类的简写

new Thread( (/*参数*/)->{//重写run方法} ).start();

参数类型、小括号、大括号可以适时忽略。参数不能忽略

lamda表达式的演变

public class Lamda {
    public static void main(String[] args) {
        interfaceWith1Method a1 = (int a)-> {System.out.println("hello" + a)};
        interfaceWith1Method a2 = new interfaceWith1Method() {
            @Override
            public void Method(int a) {
                System.out.println("hello" + a);
            }
        };
        a1.Method(1);
        a2.Method(2);
    }
}
interface interfaceWith1Method{
    abstract void Mehod(int a);
}

线程状态

停止线程

//让线程停止的方法
//1.建议线程正常停止, 利用次数,不建议死循环
//2.设置标志位flag。
//3.不使用stop或destroy等过时方法或JDK不建议的方法
public class TestStop implements Runnable{
    //此例使用标志位法
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while(flag){
            System.out.println("thread---run:" + i++);
        }
    }

    public void stop(){
        flag = false;
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();
        for (int i = 0; i < 1000; i++){
            System.out.println("main" + i);
            if(i == 900){
                testStop.stop();
                System.out.println("线程停止");
            }
        }
    }
}

线程休眠

Thread.sleep(100/*毫秒*/);
//提高线程发生的可能性

sleep不会释放锁。

线程礼让

礼让线程,让当前线程暂停,但是不阻塞。

暂停:由运行状态进入就绪状态,等待cpu调度。

调度结果看CPU

线程强制执行Join

类似插队

public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <= 1; i++){
            System.out.println("我插队来了" + i);
        }
    }

    public static void main(String[] args) throws Exception {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();
        for (int i = 1; i <= 10; i++){
            if (i == 5)
                thread.join();   //线程强制执行
            System.out.println("main 正在运行" + i);
        }
    }
}

线程状态

Thread.State

 

public class TestThreakState implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1; i++) {   //休眠等待。
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("--------");
    }
    public static void main(String[] args) throws Exception {
        TestThreakState testThreakState = new TestThreakState();
        Thread thread = new Thread(testThreakState);
        System.out.println(thread.getState());  //创建状态
        thread.start();  //线程运行
        while(thread.getState() != Thread.State.TERMINATED){
            Thread.sleep(300);
            System.out.println(Thread.currentThread().getName() + " " +Thread.currentThread().getState());//自己的线程状态
            System.out.println(thread.getName()+" "+thread.getState());  
            //获取另一条线程的状态
        }
    }
}

线程优先级

优先级(1~10)高只是意味着被调度的概率高

获取和设置.getPriority() .setPriority(int x);

public class TestPriority  {
    public static void main(String[] args) {
        Runnable thread = new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+ "-->" + Thread.currentThread().getPriority());
            }
        }; //创建一个 Runnable对象
        //创建线程并设置优先级
        Thread thread1 = new Thread(thread);
        thread1.setPriority(1);

        Thread thread2 = new Thread(thread);
        thread2.setPriority(5);
        
        Thread thread3 = new Thread(thread);
        thread3.setPriority(10);

        thread3.start();
        thread2.start();
        thread1.start();
    }
}

守护线程

线程分为守护线程和用户线程。

虚拟机不用等待守护线程执行完毕,用户线程停止,虚拟机停止工作。

设置守护线程

thread.setDaemon(true);

线程同步机制(锁)

多个线程访问同一个对象,需要排队、加锁。

队列

锁(synchronized)(隐式)

同步方法

加了synchronized的方法必须获得调用该方法的对象的锁才能执行,否则线程会阻塞。方法一旦执行,就会独占锁。直到方法结束,才释放锁。

synchronized默认锁的对象是this,类本身。

两种锁的方法

public class TestAccount implements Runnable{
    @Override
    //锁的是TestAccount对象
    public synchronized void run() {

    }
}
public class TestAccount implements Runnable{
    @Override
    public  void run() {
        synchronized(/*要锁的对象*/){
            /*代码块*/
        }
    }
}

例子:

//多线程操作同一个对象
public class TestThreadDemo01 implements Runnable{
    //这个类可以看成一个票站,每个线程看成买票的。
    private int ticketNum ;  //票的数量

    public TestThreadDemo01(int ticketNum) {
        this.ticketNum = ticketNum;
    }
    @Override
    public   void  run(){
        
        while(true){
            synchronized (this){
                if(ticketNum <=0){
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+
                                   " 拿到了第 "+ ticketNum -- + " 张票");
            }
        }
    }
    public static void main(String[] args) {
        TestThreadDemo01 testThreadDemo01 = new TestThreadDemo01(10); 
        //生成一个拥有10张票的票站
        new Thread(testThreadDemo01,"张三").start();   //买票
        new Thread(testThreadDemo01,"李四").start();
        new Thread(testThreadDemo01,"王五").start();
        Thread thread = new Thread(()->{
            System.out.println(1);
        });
    }
}

死锁

多个线程占有一些共享资源;线程等待其他线程释放资源而停止执行的情形,叫做死锁。

当某一同步块拥有两个以上锁时,可能产生死锁。

产生的四个条件

1.互斥:一个资源每次只能被一个线程调用。

2.请求与保持:一个线程因阻塞而等待,对已获得的资源保持不放。

3.不剥夺:线程获得的资源,在未使用完之前不得被剥夺

4.循环等待:若干线程之间形成一种头尾相接的循环等待资源关系。

Lock锁(显式)

public class TestLock implements Runnable{
    int ticketNums;
    ReentrantLock lock = new ReentrantLock();
    public TestLock(int ticketNums) {
        this.ticketNums = ticketNums;
    }
    @Override
    public void run() {
        while(true){
                try {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lock.lock();   //锁
                    if(ticketNums >= 1)
                        System.out.println(Thread.currentThread().getName()+" " + ticketNums --);
                    else
                        break;
                }finally {
                    lock.unlock();   //开锁
                }

        }
    }
    public static void main(String[] args) {
        TestLock testLock = new TestLock(10);//10张票
        new Thread(testLock,"张三").start();
        new Thread(testLock,"李四").start();
        new Thread(testLock,"王五").start();
    }
}

线程协作(生产消费)

wait()和notify()。

wait() :导致当前线程等待,直到另一个线程调用该对象的notify()或者notifyAll()方法

注意:wait()和notify()只能在同步方法(synchronized)中使用。

public class TestPV {
    public static void main(String[] args) {
        Containner containner = new Containner(10);//生成一个100的缓冲区
        new Producer(containner).start();
        new Consumer(containner).start();
    }
}

//产品类
class Produce {
    int id;

    public Produce(int id) {
        this.id = id;
    }
}


//生产者类
class Producer extends Thread {
    Containner containner;

    public Producer(Containner containner) {
        this.containner = containner;
    }

    @Override
    public void run() {
        int i = 1;
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            containner.pop(new Produce(i));  //往容器里放产品
            i++;
        }
    }
}

//消费者类
class Consumer extends Thread {
    Containner containner;

    public Consumer(Containner containner) {
        this.containner = containner;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            containner.push();
        }
    }
}

//缓冲区
class Containner {
    int maxNum;  //缓冲区大小
    int currentNum = 0;
    Produce[] containner;

    public Containner(int maxNum) {
        this.maxNum = maxNum;
        containner = new Produce[maxNum];
    }

    //缓冲区

    //生产者放入产品
    public synchronized void pop(Produce produce) {
        if (currentNum < maxNum) {
            containner[currentNum] = produce;
            System.out.println("生产" + produce.id);
            currentNum++;
            notifyAll();//提醒有产品了
        } else {
            try {
                System.out.println("产品满了");
                wait();//产品满了
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //消费者拿出产品
    public synchronized void push() {
        //判断有没有产品
        if (currentNum > 0) {
            currentNum--;
            System.out.println("消费了产品" + containner[currentNum].id);

            notifyAll();  //提醒 我已经消费了
        } else {
            try {
                System.out.println("产品不足");
                wait(); //产品不足
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程池

线程用完之后不用销毁,放回线程池。避免了生成销毁线程造成的资源浪费。

思路:创建多个线程,放入线程池中,使用时获取线程,使用完后放回线程池。

好处:提高响应速度,降低资源消耗,便于管理。

shutdown();不再接受线程任务。不是停止。

线程池例子:

public class TestPool {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);  
        //new个线程池
        service.execute(new MyThread());   //将继承了Runnable的类的对象放入
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.shutdown();  //不再接受任务
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值