java高级编程--多线程的使用

创建多线程的两种方式

继承Thread类的方式

一:实现步骤

  1. 创建一个继承股Thread的子类
  2. 重写Thread类的run()方法
  3. 创建Thread类的子类对象
  4. 通过子类对象调用strat()开启线程并调用run()方法;
/**
 * @author 宇戰天
 *
 * @description:遍历1-40之内的偶数
 *
 * @create2020-07-10-16:22
 */


//1.创建一个继承与Thread的子类
class MyThread extends Thread {
    //2.重写Thread的run()方法

    @Override
    public void run() {

        for (int i = 0; i < 40; i++) {
            if(i%2 ==0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }

        }
    }
}
public class ThreadTest {

    public static void main(String[] args) {
        //3创建Thread的子类对象
        MyThread t1 = new MyThread();

        MyThread t2 = new MyThread();

        //4通过此对象实例调用start()方法开启线程
        t1.start();

        t2.start();

        //创建对比主线程
        for (int i = 0; i < 40; i++) {
            if (i % 2 ==0){
                System.out.println(Thread.currentThread().getName()+":"+i+"  main");
            }

        }




    }
}

运行结果

在这里插入图片描述

线程的常用方法

  1. start(): 启动线程,并执行对象的run()方法;
  2. run(): 线程在被调度时执行的操作;
  3. getName(): 返回线程的名称;
  4. currentThread:返回执行当前代码的线程;
  5. setName(String name):设置该线程名称;
/**
 * @author 宇戰天
 * @description:
 * 方式一:
 * 设置当前线程的名字setName();
 * 为子线程时对象实例.setName(线程名);设置该线程名
 * 在main方法中设置线程名时需要先通过currentThread()获取当前代码的线程在设置线程名
 * Thread.currentThread().setName("线程名");
 * 方式二:
 * 在子类对象中添加Thread(String)的构造器在实例化线程时直接初始化线程名
 *
 * @create2020-07-10-18:42
 */
public class SetNameMethod {

    public static void main(String[] args) {
        //实例化Thread的子类对象
        UpdateThreadName u1 = new UpdateThreadName();

        u1.setName("我是子线程");

        //子类对象调用start()开启线程并调用器run()方法
        u1.start();

        //添加主线程对比项
        Thread.currentThread().setName("我是主线程");

        for (int i = 0; i < 20; i++) {

            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }

    }
}


//创建Thread的子类对象
class UpdateThreadName extends Thread{

    //提供构造器

    public UpdateThreadName() {
    }

    public UpdateThreadName(String name) {
        super(name);
    }
//重写run();
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {

            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
    }
}

运行结果
在这里插入图片描述
6. yield();释放当前cpu 的执行权限

/**
 * @author 宇戰天
 * @description:
 * yield()释放当前CPU的执行权限
 * @create2020-07-10-19:03
 */
public class UserYield {

    public static void main(String[] args) {

        YieldMethod y1 = new YieldMethod();
        y1.setName("子线程");
        y1.start();

        for (int i = 0; i < 50; i++) {

            if (i % 2 != 00){

                System.out.println(Thread.currentThread().getName() + "  " + i);

            }

        }

    }

}


class YieldMethod extends Thread{


    @Override
    public void run() {

        for (int i = 0;i <100;i++){

            if (i % 2 ==0){
                System.out.println(Thread.currentThread().getName() + "  " + i);
            }
            if (i ==20){
                yield();
            }
        }

    }
}
  1. join():当某个程序执行流中调用其他线程的join() 方法时,调用线程将被阻塞,直到join() 方法加入的join 线程执行完为止;
  2. isAlive():返回boolean,判断线程是否还活着
  3. sleep(long millis):令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。
/**
 * @author 宇戰天
 * @description:
 * join()方法在线程a中调用线程b的join()方法,此时线程a就进入停止状态知道线程b执行完为止
 *sleep();让当前线程休眠,只等时间内为阻塞状态
 * isAlive()判断当前线程是否存活
 * @create2020-07-10-19:28
 */
public class JoinMethod {

    public static void main(String[] args) {

        JoinIn method23 = new JoinIn();

        method23.setName("线程b");
        method23.start();

        Thread.currentThread().setName("线程a");
        for (int i = 0; i < 50; i++) {

            System.out.println(Thread.currentThread().getName() + "  " + i);
            if (i==25){
                try {
                    //在在线程a中调用线程b的join();
                    method23.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }
        //判断当前线程是否存活
        System.out.println(method23.isAlive());
    }
}


class JoinIn extends Thread{


    @Override
    public void run() {
        for (int i = 0;i<50;i++){

            //当前线程休眠时间
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "   " + i);
        }
    }
}
线程的优先级

线程的优先级等级

  • MAX_PRIORITY:10
  • MIN _PRIORITY:1
  • NORM_PRIORITY:5(默认优先级)
    如何设置线程的优先级
  • getPriority() :返回线程优先值
  • setPriority(intnewPriority) :改变线程的优先级
    注意
  • 线程创建时继承父线程的优先级;
  • 低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用

创建线程的方式二:实现Runnable接口

实现思路
1.创建一个实现Runnable接口的实现类;
2.实现类实现Runnable中的抽象方法run();
3.创建实现类的对象;
4.将此实现类作为参数传递给Thread的构造器中并创建Thread类的对象;
5.通过Thread类的对象调用start()启动线程并调用Runnable类型的target的run();

/**
 * @author 宇戰天
 * @description:
 * 创建多线程的第二种方式:实现Runnable接口
 * 1.创建一个实现Runnable接口的实现类;
 * 2.实现类实现Runnable中的抽象方法run();
 * 3.创建实现类的对象;
 * 4.将此实现类作为参数传递给Thread的构造器中并创建Thread类的对象;
 * 5.通过Thread类的对象调用start()启动线程并调用Runnable类型的target的run();
 * @create2020-07-10-21:47
 */

//1.创建一个实现Runnable接口的实现类
class Thread2 implements Runnable{
        //2.实现类实现Runnable中的抽象方法run();
    @Override
    public void run() {
        for (int i = 0; i < 40; i++) {

            System.out.println(Thread.currentThread().getName() + " " + i);

        }
    }
}
public class ImplementsThreadSecondMethod {

    public static void main(String[] args) {
        //3.创建实现类的对象
        Thread2 t2 = new Thread2();
        //4.将此实现类作为参数传递给Thread的构造器中并创建Thread类的对象
        Thread thread = new Thread(t2);
        thread.setName("线程");
        //5.通过Thread类的对象调用start()启动线程并调用Runnable类型的target的run();
        thread.start();
    }


}

线程安全

在java中我们通过同步机制来解决线程的安全问题;解决线程通行常用的三种方法分别为lock锁方式同步代码块同步方法

一:同步代码块方式解决线程安全问题
  1. 定义
synchronized (同步监听器){	
		
			//需要被同步的代码
}
  1. 说明
    1. 操作共享数据的代码为需要被同步的代码
    2. 共享数据多个线程共同操作的变量
    3. 同步监听器:俗称锁任何一个对象都可以充当锁,但是多个线程必须共用同一个锁。

实现Runnable接口方式

/**
 * @author 宇戰天
 * @description:
 *
 *通过实现Runnable接口方式创建三个线程实现卖票功能
 * 步骤:
 * 1.创建一个Runnable接口的类;
 * 2.实现Runnable中的抽象方法run();
 * 3.创建实现对象
 * 4.创建Thread对象,此将实现Runnable的子类对象作为参数传递到Thread的构造器中;
 * 5.通过Thread对象调用start()开启线程
 *
 * 用同步代码块方式解决线程安全问题
 *       synchronized(监听器) {
 *
 *              需要同步打代码
 *     }
 * @create2020-07-12-12:31
 */

public class SellTicketTest {

    public static void main(String[] args) {
        //3.创建实现的对象
        TicketWindow chengDu = new TicketWindow();

        //4.创建Thread对象,此将实现Runnable的子类对象作为参数传递到Thread的构造器中

        Thread sellWindows1 = new Thread(chengDu);
        Thread sellWindows2 = new Thread(chengDu);
        Thread sellWindows3= new Thread(chengDu);

        //设置线程名
        sellWindows1.setName("一号窗口");
        sellWindows2.setName("二号窗口");
        sellWindows2.setName("三号窗口");

        //5.通过Thread对象调用start()开启线程
        sellWindows1.start();
        sellWindows2.start();
        sellWindows3.start();

    }


}
//1.传建一个实现Runnable接口的子类
class TicketWindow implements  Runnable{
    //售票数量(多个线程共享此数据)
    private  int ticket =100;

    //定义同步监听器-->锁
    Object obj = new Object();

    //2.重写Runnable中的抽象方法run()
    @Override
    public void run() {
        while (true){

            synchronized(obj) {

                if (ticket >0){
    //一秒后开启线程为其他线程执行抢占CPU资源提供条件
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 卖票,票的编号为:" + ticket);

                    ticket--;
                }else{
                    break;
                }
            }

        }
    }
}

继承Thread类

**
 * @author 宇戰天
 * @description* 通过继承Thread方式创建三个进程实现卖票功能
 * 1.创建继承Thread的子类;
 * 2.重写T和read中的run();
 * 3.创建Thread的子类对象;
 * 4.通过子类对象调用start()方法开启线程
 *
 * 通过synchronized(同步监视器){
 *
 *     需要被同步的代码
 * }
 * 解决线程安全问题
 * @create2020-07-12-13:28
 */
public class SellTicketTest1 {

    public static void main(String[] args) {
        //3.创建Thread类的子类的对象
        sellWindows1 t1 = new sellWindows1();
        sellWindows1 t2 = new sellWindows1();
        sellWindows1 t3 = new sellWindows1();

        //更改线程名
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        //4.通过此子类对象调用start()开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}

//1.创建一个继承于Thread的子类
class sellWindows1 extends  Thread{
    //所有对象共享此变量
    private static int  ticket = 100;
    //创建同步锁
    private static Object obj = new Object();
//2.重写Thread中的run
    @Override
    public void run() {

        while (true){

            synchronized (obj){
                if (ticket>0){

                        //提高其他线程出现的几率
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " 卖票,票号为:" + ticket);
                    ticket--;

                }else{
                    break;
                }
            }

        }
    }
}
同步方法解决线程安全问题

实现Runnable接口方式

/**
 * @author 宇戰天
 * @description:
 *
 * 同步方法解决线程安全问题
 * @create2020-07-12-14:13
 */
public class SellTicketTest3 {

    public static void main(String[] args) {
        //3.创建实现的对象
        TicketWindow3 chengDu = new TicketWindow3();

        //4.创建Thread对象,此将实现Runnable的子类对象作为参数传递到Thread的构造器中

        Thread sellWindows1 = new Thread(chengDu);
        Thread sellWindows2 = new Thread(chengDu);
        Thread sellWindows3 = new Thread(chengDu);

        //设置线程名
        sellWindows1.setName("一号窗口");
        sellWindows2.setName("二号窗口");
        sellWindows2.setName("三号窗口");

        //5.通过Thread对象调用start()开启线程
        sellWindows1.start();
        sellWindows2.start();
        sellWindows3.start();

    }


}
//1.传建一个实现Runnable接口的子类
class TicketWindow3 implements  Runnable{
    //售票数量(多个线程共享此数据)
    private  int ticket =100;


    //2.重写Runnable中的抽象方法run()
    @Override
    public void run() {
        while (true) {

            show();

        }
    }
    private synchronized void show(){

        if (ticket >0){
            //一秒后开启线程为其他线程执行抢占CPU资源提供条件
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + " 卖票,票的编号为:" + ticket);

            ticket--;
        }
    }

}

继承Thread子类的方式

/**
 * @author 宇戰天
 * @description:
 * @create2020-07-12-14:35
 */
public class sellTicketTest4 {

    public static void main(String[] args) {
        //3.创建Thread类的子类的对象
        sellWindows4 l1 = new sellWindows4();
        sellWindows4 l2 = new sellWindows4();
        sellWindows4 l3 = new sellWindows4();

        //更改线程名
        l1.setName("窗口1");
        l2.setName("窗口2");
        l3.setName("窗口3");

        //4.通过此子类对象调用start()开启线程
        l1.start();
        l2.start();
        l3.start();
    }
}

//1.创建一个继承于Thread的子类
class sellWindows4 extends  Thread{
    //所有对象共享此变量
    private static int  ticket = 100;

    //2.重写Thread中的run
    @Override
    public void run() {

        while (true){

            show();

        }
    }

    private static synchronized  void show(){
        if (ticket>0){

            //提高其他线程出现的几率
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 卖票,票号为:" + ticket);
            ticket--;

        }

    }
}
使用lock锁方式
/**
 * @author 宇戰天
 * @description:
 * 使用lock方式解决卖票中个线程安全问题
 * @create2020-07-12-15:51
 */
//创建实现Runnable接口的实现子类
class windowsLock implements Runnable {


    private int  ticket = 100;

    //实例化ReentrantLock

     private  ReentrantLock lock1 = new ReentrantLock();

     //重写实现子类的run方法
    @Override
    public void run() {


        while(true){
            try{

                //调用锁定的方法lock()
                lock1.lock();

                if (ticket >0){

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 售票,票号为:" + ticket);
                    ticket--;
                }


            }finally{

                //调用解锁方式
                lock1.unlock();
            }


        }

    }
}

public class UseLockRelolveSafelty {

    public static void main(String[] args) {
        //创建实现子类的对象

        windowsLock w2 = new windowsLock();

        //将此实现子类对象传给Thread,创建Thread子类
        Thread q1 =new Thread(w2);
        Thread q2 =new Thread(w2);
        Thread q3 =new Thread(w2);

        //设置线程名
        q1.setName("窗口1");
        q2.setName("窗口2");
        q3.setName("窗口3");

        //调用start开启线程
        q1.start();
        q2.start();
        q3.start();
    }



}

线程通信

wait() 与notify() 和notifyAll()

  • wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行
  • notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
  • notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
    注意
    这三个方法只有在synchronized方法或synchronized代码块中才能使用
/**
 * @author 宇戰天
 * @description:
 *生产者和消费者问题
 * 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,
 * 店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员
 * 会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品
 * 了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
 * @create2020-07-12-17:49
 */
//被共享的数据
class Clerk{

    private  int productNum = 0;
//生产产品的方法
    public synchronized void addProduct() {

        if(productNum<20){
            productNum++;
            System.out.println(Thread.currentThread().getName() + "开始生产第:" + productNum + "产品");
//唤醒消费者
            notify();

        }else{

            try {
                wait();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


//    售卖商品的方法
    public synchronized void sellProductor() {

        if (productNum>0){

            System.out.println(Thread.currentThread().getName() + "购买了第" + productNum + "个产品");
            productNum--;
//唤醒生产者
            notify();
        }else{

            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


//生产者线程
class Productor extends Thread{
    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "工厂开始生产产品 ......");
        while(true){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.addProduct();
        }
    }
}


//消费者线程
class Customer extends Thread{

    private Clerk clerk;

    public Customer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始购买产品......");

        while(true){

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            clerk.sellProductor();
        }


    }

}
public class CustomerAndProduct {


    public static void main(String[] args) {
        Clerk clerk = new Clerk();


//        创建生产工厂

        Productor p1 = new Productor(clerk);
        p1.setName("工厂1");

//        创建生产者对象实例
        Customer c1 = new Customer(clerk);
        c1.setName("消费者1");

        Customer c2 = new Customer(clerk);
        c2.setName("消费者2");
//    通过对象调用start()方法开启线程
        p1.start();
        c1.start();
        c2.start();
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值