超详细Java多线程学习笔记

1、Thread(重点)

  1. 自定义线程类继承Thread类
  2. 重写==run()==方法,编写线程执行体
  3. 创建线程对象,调用==start()==方法启动线程

代码示例:

package testthread1;

/**
 *
 * 创建线程方式一:继承Thread类,重新run()方法,电泳start开启线程
 */
public class TestThread1 extends Thread{
   

   public void run()
    {
   
        //run方法线程体
        for(int i = 0; i < 10; i++)
            System.out.println("我在看代码——————"+ i);
    }
   
    public static void main(String[] args) {
   
       //main线程, 主线程
       
       //创建一个线程对象
       TestThread1 testThread1 = new TestThread1();
       //调用start()方法开启线程
       testThread1.start();
       
       for(int i = 0; i < 10; i++)
       {
   
           System.out.println("我在学习多线程——————" + i);
       }
    }
    
}

结果:

run:
我在学习多线程——————0
我在学习多线程——————1
我在学习多线程——————2
我在学习多线程——————3
我在看代码——————0
我在看代码——————1
我在看代码——————2
我在看代码——————3
我在学习多线程——————4
我在学习多线程——————5
我在学习多线程——————6
我在学习多线程——————7
我在学习多线程——————8
我在学习多线程——————9
我在看代码——————4
我在看代码——————5
我在看代码——————6
我在看代码——————7
我在看代码——————8
我在看代码——————9
成功构建 (总时间: 0 秒)

可以看到两个线程同时进行。

注意:线程不一定执行,CPU安排调度上面的程序每次执行结果可能都不相同,若运行后没有出现类似情况,可以将i的循环调制2000次,此时结果比较明显。

2、Runnable(重点)

  1. 定义MyRunnable类实现Runnable接口
  2. 实现run() 方法,编写线程执行体
  3. 创建线程对象,调用start() 方法启动线程

代码示例:

//创建线程方法2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class TestThread3 implements Runnable{
   
    @Override
    public void run(){
   
        //run方法线程体
        for(int i = 0; i < 20; i++)
            System.out.println("我在看代码————" + i);
    }

    public static void main(String[] args){
   
        //创建runnable接口实现类对象
        TestThread3 testThread3 = new TestThread3();

        //创建线程对象,通过线程对象来开启我们的线程代理
        //Thread thread = new Thread(testThread3);
        //thread.start();
        new Thread(testThread3).start();

        for(int i = 0; i < 20; i++){
   
            System.out.println("我在学习多线程—————" + i);
        }
    }
}

结果:

我在学习多线程—————0
我在学习多线程—————1
我在看代码————0
我在看代码————1
我在看代码————2
我在看代码————3
我在看代码————4
我在看代码————5
我在看代码————6
我在看代码————7
我在看代码————8
我在看代码————9
我在学习多线程—————2
我在学习多线程—————3
我在学习多线程—————4
我在学习多线程—————5
我在学习多线程—————6
我在学习多线程—————7
我在学习多线程—————8
我在学习多线程—————9

总结:

继承Thread类

子类继承Thread类具备多线程能力
启动线程:子类对象.start()
不建议使用:避免OOP单继承局限性

实现Runnable接口

实现接口Runnable具有多线程能力
启动线程:传入目标对象+ Thread对象.start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

3、初识并发问题

代码示例:


//多个线程同时操作同一个对象
//买火车票的例子

//发现问题:多个线程操作同一个资源的情况下,线程不安全,数据混乱
public class TestThread4 implements Runnable{
   

    private  int tickNums = 10;

    @Override
    public void run(){
   
        while(true){
   
            if(tickNums <= 1){
   
                break;
            }
           try{
   
                Thread.sleep(200);
           }catch (InterruptedException e){
   
                e.printStackTrace();
           }
            System.out.println(Thread.currentThread().getName() + "-->拿到了第" + tickNums-- + "票");
        }
    }
    public static void main(String[] args) {
   

        TestThread4 ticket = new TestThread4();


        new Thread(ticket,"小明").start();
        new Thread(ticket,"小红").start();
        new Thread(ticket,"黄牛").start();


    }
}

结果:

黄牛–>拿到了第10票
小明–>拿到了第8票
小红–>拿到了第9票
小红–>拿到了第6票
黄牛–>拿到了第5票
小明–>拿到了第7票
小明–>拿到了第4票
小红–>拿到了第4票
黄牛–>拿到了第4票

小明–>拿到了第2票
小红–>拿到了第1票
黄牛–>拿到了第3票

练习:多线程龟兔赛跑

4、实现Callable接口(了解即可)

  1. 实现Callable接口,需要返回值类型
  2. 重写call方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  5. 提交执行: Future result 1 = ser.submit(t1);
  6. 获取结果: boolean r1 = result1.get()
  7. 关闭服务: ser.shutdownNow();

5、静态代理

需求:

你:真实角色
婚庆公司:代理你,帮你处理结婚的事
结婚:实现都实现结婚接口即可

代码示例:

/*静态代理模式总结:
                   真实对象和代理对象都要实现同一个接口
                   代理对象要代理真实角色

  好处:代理对象可以做很多真实对象做不了的事情
        真实对象专注做自己的事情
       
*/
public class StaticProxy {
   
    public static void main(String[] args) {
   

        new Thread( ()-> System.out.println("我爱你") ).start();
        new weddingCompany(new You()).HappyMarry();
//        You you = new You();  //你要结婚
//
//        weddingCompany weddingCompany = new weddingCompany(you);
//        weddingCompany.HappyMarry();
    }
}

interface  Marry{
   

    void HappyMarry();
}

//真实角色,你去结婚
class You implements Marry{
   
    @Override
    public void HappyMarry(){
   
        System.out.println("张三要结婚了");
    }
}

//代理角色,帮助你结婚
class weddingCompany implements Marry{
   
    //代理谁-->真实目标角色
    private Marry target;

    public weddingCompany(Marry target){
   
        this.target = target;
    }

    @Override
    public void HappyMarry(){
   
        before();
        this.target.HappyMarry();  //这就是真实角色
        after();
        
    }
    private void after(){
   
        System.out.println("结婚之后,收尾款");
    }
    private void before(){
   
        System.out.println("结婚之前,布置现场");
    }

}

图解设计模式------Proxy(代理)模式

六、Lamda表达式

6.1 为什么要使用lamda表达式?

  • 避免匿名内部类定义过多
  • 可以让你的代码看起来很简洁
  • 去掉了一堆没有意义的代码,只留下核心的逻辑

理解Runctional interface(函数式接口)是学习Java8 lamda表达式的关键所在。

函数式接口的定义:

  1. 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
  2. 对于代码,我们可以通过lamda表达式来创建该接口的对象

代码简化过程:

package Lambda;


//推到lambda表达式
public class TestLambda1 {
   

    //3、静态内部类
    static class Like2 implements ILike{
   
        @Override
        public void lambda(){
   
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
   
        ILike like = new Like();
        like.lambda();

        like 
  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

胡小冰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值