Java基础4

线程:
创建线程:
在这里插入图片描述

package Thread;

/**
 * 创建多线程的第一种方式:创建Thread类的子类
 * java.lang.Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类
 * 实现步骤:
 * 1.创建一个Thread类的子类
 * 2.在Thread类的子类中重写Thread类中的run方法,设置线程任务
 * 3.创建Thread类的子类对象
 * 4.调用Thread类中的方法start方法,开启新的线程
 * void start()使该线程开始执行,虚拟机调用该线程的run方法
 * 结果是两个线程并发地执行,当前线程和另外一个线程
 * 多次调用一个线程是非法的,特别是当线程已经结束,不能再重新启动
 */

public class ThreadDemo1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("run:"+i);
        }
    }
}

package Thread;

public class ThreadMainDemo {
    public static void main(String[] args) {
        ThreadDemo1 mt = new ThreadDemo1();

        mt.start();

        for (int i = 0; i < 20; i++)
            System.out.println("main:"+i);
    }
}

在这里插入图片描述
在这里插入图片描述
Thread类的常用方法:

package Thread;

/**
 * 创建多线程的第一种方式:创建Thread类的子类
 * java.lang.Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类
 * 实现步骤:
 * 1.创建一个Thread类的子类
 * 2.在Thread类的子类中重写Thread类中的run方法,设置线程任务
 * 3.创建Thread类的子类对象
 * 4.调用Thread类中的方法start方法,开启新的线程
 * void start()使该线程开始执行,虚拟机调用该线程的run方法
 * 结果是两个线程并发地执行,当前线程和另外一个线程
 * 多次调用一个线程是非法的,特别是当线程已经结束,不能再重新启动
 */

public class ThreadDemo1 extends Thread {
    @Override
    public void run() {
        /*for (int i = 0; i < 20; i++) {
            System.out.println("run:"+i);}*/
        /*String name = getName();
        System.out.println(name);*/

        Thread t = Thread.currentThread();
        //System.out.println(t);

        String name = t.getName();
        System.out.println(name);

    }
}

package Thread;

/**
 * Thread类的常用方法:
 * 构造方法:
 * public Thread():分配一个新的线程对象
 * public Thread(String name):分配一个指定名字的新的线程对象
 * public Thread(Runnable target):分配一个带有指定目标的线程对象
 * public Thread(Runnable target,String name):分配一个有目标有名字的线程对象
 *
 * 常用方法:
 * public String getName():获取当前线程名称
 * public void start():导出此线程开始执行;Java虚拟机调用此线程的run方法
 * public void run():此线程要执行的任务在此处定义代码
 * public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停
 * public static Thread currentThread():返回对当前正在执行的线程对象的引用
 */

public class ThreadDemo2 {

    public static void main(String[] args) {
        ThreadDemo1 mt = new ThreadDemo1();
        mt.start();

        new ThreadDemo1().start();
        new ThreadDemo1().start();



    }
}

创建线程的第二种方式:实现Runnable接口
在这里插入图片描述

package Thread;

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

package Thread;

/**
 * 实现步骤:
 * 1.创建一个Runnable接口的实现类
 * 2.在类中重写Runnable接口的run方法,设置线程任务
 * 3.创建一个Runnable接口的实现类对象
 * 4.创建一个Thread类对象,构造方法中传递Runnable接口的实现类
 * 5.调用Thread类中的start方法,开启新的线程执行run方法
 *
 * 实现Runnable接口创建多线程的好处:
 * 1.避免了单继承的局限性
 * 2.增强了程序的扩展性,降低了程序的耦合性(把设置线程任务和开启线程进行了分离)
 *
 */

public class ThreadMainDemo {
    public static void main(String[] args) {
        /*ThreadDemo1 mt = new ThreadDemo1();

        mt.start();

        for (int i = 0; i < 20; i++)
            System.out.println("main:"+i);*/
        RunnableImpl run = new RunnableImpl();
        Thread t = new Thread(run);
        t.start();

        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}

匿名内部类方式实现线程的创建:

package Thread;

/**
 * 匿名内部类的作用:简化代码
 * 把子类继承父类,重写父类的方法,创建子类对象合一步完成
 * 把实现类接口,重写接口中的方法,创建实现类对象合成一步
 * 匿名内部类的产物:子类/实现类对象,而这个对象没有名字
 */

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

        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+"Thread");
                }
            }
        }.start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+"Runnable");
                }
            }
        }).start();
    }
}

线程安全问题:
解决方法:
1.同步代码块
在这里插入图片描述

package Thread;

/**
 * 解决线程问题的第一种方案:使用同步代码块
 * 格式:synchronized(锁对象){
 *     访问了共享数据的代码
 * }
 * 注意:
 * 1.同步代码块中的锁对象,可以是任意对象
 * 2.必须保证多个线程使用的锁对象是同一个
 * 3.锁对象作用:
 * 把同步代码块锁住,只让一个线程在同步代码块中执行
 */

public class RunnableImpl2 implements Runnable {
    private int ticket = 100;
    Object obj = new Object();

    @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--;
                }
            }
        }
    }
}

2.同步方法

public synchronized 返回值类型 方法名(参数列表){
//同步代码
//锁对象是this
}

3.锁机制
在这里插入图片描述
线程状态:
在这里插入图片描述
线程间通信:

package Thread;

/**
 * 线程之间的通信:
 * 创建一个顾客线程:告知老板要的包子种类和数量,调用wait方法,放弃cpu的执行,进入到waiting状态(无限等待)
 * 创建一个老板线程:花了5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子
 *
 * 注意:顾客和老板线程必须使用代码块包裹起来,包子等待和唤醒只能有一个执行
 * 同步使用的锁对象必须保证唯一
 * 只有锁对象才能调用wait和notify方法
 *
 * Object类中的方法:
 * void wait():在其他线程调用此对象的notify()方法或notifyAll()方法前,导致当前线程等待
 * void notify():唤醒在对象监视器上等待的单个线程,会继续执行wait方法之后的代码
 */

public class producterConsumerDemo1 {
    public static void main(String[] args) {
        Object obj = new Object();
        //创建一个顾客线程
        new Thread(){
            @Override
            public void run() {
                while(true){
                    //保证等待和唤醒线程只能有一个执行,需要使用同步技术
                    synchronized (obj){
                        System.out.println("告知老板要的包子种类和数量");
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //唤醒之后执行的代码
                        System.out.println("包子已经做好了,开吃");
                    }
                }
            }
        }.start();
        //创建一个老板线程
        new Thread() {
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(5000);//花5秒做包子
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj){
                        System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子了");
                        obj.notify();
                    }
                }
            }
        }.start();

    }
}

生产者与消费者模型:
在这里插入图片描述
代码实现:

package Thread;

/**
 * 设置包子的属性:
 * 皮、馅、包子的状态
 */

public class BaoZi {
    String pi;
    String xian;
    boolean flag = false;
}

package Thread;

/**
 * 生产者(包子铺):是一个线程类,可以继承Thread
 * 设置线程任务:生产包子
 * 对包子的状态进行判断:true(有包子)   包子铺调用wait方法计入等待状态
 * false:没有包子   包子铺生产包子   增加一些趣味:交替生产两种包子
 * 有两种状态(i%2==0),包子铺生产好了包子,修改包子的状态为true,唤醒吃货线程,让吃货吃包子
 *
 * 注意:包子铺线程和包子线程是互斥关系,必须使用同步技术保证两个线程只有一个在执行
 * 锁对象必须保证唯一,可以使用包子对象作为锁对象
 * 包子铺和吃货的类就需要把包子对象作为参数传递进来:
 * 1.需要在成员位置创建一个包子变量
 * 2.使用带参数构造方法,为这个包子变量赋值
 */

public class BaoZiPu extends Thread {
    //1.需要在成员位置创建一个包子变量
    private BaoZi bz;
    //2.使用带参数构造方法,为这个包子变量赋值
    public BaoZiPu(BaoZi bz) {
        this.bz = bz;
    }
    //设置线程任务,生产包子
    @Override
    public void run() {
        int count = 0;
        while(true) {
            //必须使用同步技术保证两个线程只有一个在执行
            synchronized (bz) {
                //对包子的状态进行判断
                if (bz.flag == true) {
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //被唤醒之后执行,包子铺生产包子
                //增加一些趣味性:交替生产两种包子
                if (count % 2 == 0) {
                    //生产薄皮,三鲜馅包子
                    bz.pi = "薄皮";
                    bz.xian = "三鲜馅";
                } else {
                    //生产冰皮、牛肉大葱馅
                    bz.pi = "冰皮";
                    bz.xian = "三鲜馅";
                }
                count++;
                System.out.println("包子铺正在生产:" + bz.pi + bz.xian + "包子");
                //生产包子需要3秒钟
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                bz.flag = true;
                bz.notify();
                System.out.println("包子铺已经好了" + bz.pi + bz.xian + "包子,吃货可以开吃了");
            }
        }
    }
}

package Thread;

/**
 * 消费者(吃货类):是一个线程类,可以继承Thread
 * 设置线程任务(run):吃包子
 * 对包子的状态进行判断:
 * false:没有包子,吃货调用wait方法进入等待
 * true:
 * 吃货吃包子,吃货吃完包子,修改包子装态为false,唤醒包子铺线程,生产包子
 */

public class ChiHho extends Thread {
    //1.需要在成员位置创建一个包子变量
    private BaoZi bz;
    //2.使用带参数构造方法,为这个包子变量赋值
    public ChiHho(BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        while (true){
            //必须使用同步技术保证两个线程只有一个在执行
            synchronized (bz){
                //对包子的状态进行判断
                if(bz.flag==false){
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //被唤醒之后的代码,吃包子
                System.out.println("吃货正在吃:" + bz.pi + bz.xian + "包子");
                //吃货吃完包子,修改包子的状态
                bz.flag = false;
                //唤醒包子铺做包子
                bz.notify();
                System.out.println("吃货已经把:" + bz.pi + bz.xian + "的包子吃完了,包子铺开始生产包子");
                System.out.println("==================================================");

            }
        }
    }
}

package Thread;

public class ThreadMainDemo4 {
    public static void main(String[] args) {
        BaoZi bz = new BaoZi();
        new BaoZiPu(bz).start();
        new ChiHho(bz).start();
    }
}

线程池:

package Thread;

public class RunnableImplDemo implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"创建了一个新的线程");
    }
}

package Thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Executors类中的静态方法:
 * static ExecutorService newFixedThreadPool(int nThreads):创建一个可用固定线程数的线程池
 * 返回值:ExecutorService接口,返回的是ExecutorService接口的实现类,
 * 我们可以使用ExecutorService接口接收(面向接口编程)
 *
 * 用来从线程池中获取线程,调用start方法,执行线程任务
 * submit(Runnable task):提交一个Runnable任务用于执行
 * 关闭销毁线程池的方法
 * void shutdown();
 *
 * 使用步骤:
 * 1.使用线程池的工厂类Executors里边提供的newFixedThreadPool生产一个指定数量的线程池
 * 2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
 * 3.调用ExecutorService中的方法submit,传递线程任务,开启线程,执行run方法
 * 4.调用ExecutorService中的方法shutdown销毁线程池
 */

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        es.submit(new RunnableImplDemo());
        es.submit(new RunnableImplDemo());
        es.submit(new RunnableImplDemo());

        es.shutdown();
    }
}

lambda表达式:
1.无参无返回值

package Thread;

/**
 * 定义一个Cook接口,内含唯一的抽象方法makeFood
 */

public interface Cook  {
    //定义无参数无返回值的方法makeFood
    public abstract void makeFood();
}

package Thread;

/**
 * Lambda表达式的格式(三个一):
 * 1.一些参数
 * 2.一个箭头
 * 3.一段代码
 *
 * (参数列表)->{一些重写方法的代码}
 * 解释说明格式:
 * ():接口中抽象方法的参数列表,没有参数,就空着,有参数就写出参数,多个参数用逗号分隔
 * ->:传递的意思,把参数传递给方法体{}
 * {}:重写接口的抽象方法的方法体
 */

public class LambdaDemo {
    //使用Lambda的标准格式调用invokeCook方法,打印输出“吃饭啦!”字样
    public static void main(String[] args) {
        invokeCook(new Cook() {
            @Override
            public void makeFood() {
                System.out.println("吃饭啦!");
            }
        });
        System.out.println("==================");

        //使用Lambda表达式
        invokeCook(()->{
            System.out.println("吃饭啦!");
        });
    }



    //定义一个方法,参数传递Cook接口,方法内部调用Cook接口中的方法makeFood
    public static void invokeCook(Cook cook){
        cook.makeFood();
    }
}

有参数有返回值:

package Thread;

public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package Thread;

import java.util.Arrays;
import java.util.Comparator;

public class PersonMainDemo {
    public static void main(String[] args) {
        Person[] arr = {
          new Person("柳岩",38),
          new Person("迪丽热巴",18),
          new Person("古力娜扎",19)
        };

        /*Arrays.sort(arr, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge()- o2.getAge();
            }
        });*/
        //使用Lanbda表达式
        Arrays.sort(arr, (Person o1, Person o2)->{
                return o1.getAge()- o2.getAge();
            }
        );

        for (Person person : arr) {
            System.out.println(person);
        }
    }
}

Lambda表达式的省略:


/**
 * Lambda表达式:是可推导,可以省略的
 * 凡是依据上下文推到出来的内容,都可以省略书写
 * 可以省略的内容:
 * 1.(参数列表):括号中的数据类型可以省略不写
 * 2.(参数列表):括号中的参数只有一个,那么类型和()都可以省略
 * 3.{一些代码}:如果{}中的代码只有一行无论是否有返回值,都可以省略({},return,分号)
 */

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值