java多线程基础

多线程

进程

一个内存中运行的应用程序,每个进程有一个独立的空间。

线程

  • 每个线程都有自己的栈空间,共用一份堆内存

同步和异步

  • 同步:排队执行,效率低但是安全
  • 异步:同时执行,效率高但是不安全
  • 并发:两个或者多个事件在同一时间段内发生
  • 并行:两个或多个事件在同一时刻发生

线程实现

方法

  1. getName()获取线程名
  2. Thread.currentThread().getName();
  3. sleep为静态方法

实现Thread

  • 构造方法
  1. new Thread();
  2. new Thread(String name)
  3. new Thread(Runnable, String name)
package com.lyq.kaikeba.codeLearn.threadLearn;

public class MyThread extends Thread{
    @Override
    public void run() {
        // 新的执行路径
        // 通过start()启动线程
    }
}

继承Runnable

package com.lyq.kaikeba.codeLearn.threadLearn;

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

    }
}

测试MyThread和MyRunnable

// 测试

package com.lyq.kaikeba.codeLearn.threadLearn;

/**
 * 多线程技术
 * 实现Runnable 与 继承Thread相比有如下优势:
 * 1. 通过创建任务,然后给线程分配的方式来实现多线程,更适合线程执行相同任务的情况
 * 2. 可以避免单继承带来的局限性
 * 3. 任务本身与线程是分离的,提高了程序的健壮性
 * 4. 后续学习的线程池,接受Runnable类型的任务,不接受Thread类型的线程
 */
public class ThreadTest {
    public static void main(String[] args) {


        // 继承Thread用法
        MyThread t1 = new MyThread();
        t1.start();

        // 实现Runnable用法
        MyRunnable r1 = new MyRunnable();
        Thread t = new Thread(r1);
        t.start();
    }
}

匿名内部类实现多线程

package com.lyq.kaikeba.codeLearn.threadLearn;

public class Demo1 {
    public static void main(String[] args) {
        // 匿名内部类实现多线程
        new Thread(){
            @Override
            public void run() {
                for(int i=0; i<10; i++){
                    System.out.println("thread " + i);
                }
            }
        }.start();

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

### 实现Runnable与继承Thread相比有如下优势:
 1. 通过创建任务,然后给线程分配的方式来实现多线程,更适合线程执行相同任务的情况
 2. 可以避免单继承带来的局限性
 3. 任务本身与线程是分离的,提高了程序的健壮性
 4. 后续学习的线程池,接受Runnable类型的任务,不接受Thread类型的线程

线程中断

  • 现在使用interrupt给线程打标记
  • stop方法已经停用
package com.lyq.kaikeba.codeLearn.threadLearn;

public class Interrupt {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable());
        t1.start();

        for(int i=0; i<10; i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 给t1添加中断标记
        t1.interrupt();

    }

    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for(int i=0; i<10; i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // e.printStackTrace();
                    System.out.println("发现了中断标记,线程自杀");
                    return;
                }
            }
        }
    }
}

守护线程

  • 线程分为守护线程和用户线程
  • 用户线程:当一个线程不包含任何用户线程时,进程结束
  • 守护线程:守护用户线程,当最后一个用户线程结束时,守护线程自动死亡  
    // 设置为守护线程  
            t1.setDaemon(true);
package com.lyq.kaikeba.codeLearn.threadLearn;

public class Interrupt {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable());
        // 设置为守护线程
        t1.setDaemon(true);
        t1.start();

        for(int i=0; i<10; i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 给t1添加中断标记
        t1.interrupt();

    }

    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for(int i=0; i<10; i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // e.printStackTrace();
                    System.out.println("发现了中断标记,线程自杀");
                    return;
                }
            }
        }
    }
}

线程同步问题

1、synchronized同步代码块(隐式锁)

  • 对一个对象(任意对象)上锁,同一时间只有一个线程能访问代码块
package com.lyq.kaikeba.codeLearn.threadLearn;

/**
 * 使用synchronized同步代码块
 */
public class Demo2 {
    public static void main(String[] args) {
        SellTicket s = new SellTicket();
        new Thread(s).start();
        new Thread(s).start();
        new Thread(s).start();

    }

    static class SellTicket implements Runnable{
        private int count = 10;
        private Object o = new Object();
        @Override
        public void run() {
            while(true){
                synchronized (o){
                    if(count>0){
                        System.out.println("开始卖票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName()+"出票成功,余票为:"+count);
                    }else{
                        break;
                    }
                }
            }
        }
    }
}

2、synchronized同步方法(隐式锁)

  • 对方法上锁
package com.lyq.kaikeba.codeLearn.threadLearn;

/**
 * 使用synchronized同步方法
 */
public class Demo3 {
    public static void main(String[] args) {
        SellTicket s = new SellTicket();
        new Thread(s).start();
        new Thread(s).start();
        new Thread(s).start();

    }

    static class SellTicket implements Runnable{
        private int count = 10;
        private Object o = new Object();
        @Override
        public void run() {
            while(true){
                boolean flag = sell();
                if(!flag)
                    break;
            }
        }

        public synchronized boolean sell(){
            if(count>0){
                System.out.println("开始卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"出票成功,余票为:"+count);
                return true;
            }
            return false;
        }

    }
}

3、显式锁:Lock

package com.lyq.kaikeba.codeLearn.threadLearn;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用Lock同步代码块
 */
public class Demo4 {
    public static void main(String[] args) {
        SellTicket s = new SellTicket();
        new Thread(s).start();
        new Thread(s).start();
        new Thread(s).start();

    }

    static class SellTicket implements Runnable{
        private int count = 10;
        private Lock l = new ReentrantLock();
        @Override
        public void run() {
            while(true){
                l.lock();
                if(count>0){
                    System.out.println("开始卖票");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count--;
                    System.out.println(Thread.currentThread().getName()+"出票成功,余票为:"+count);
                }else{
                    break;
                }
                l.unlock();

            }
        }
    }
}

公平锁和非公平锁

  • 公平锁:排队抢占资源
  • 非公平锁:抢占式抢资源
  • 上述三种锁默认为非公平锁
  • Lock可以使用公平锁:Lock l = new ReentrantLock(true);

线程死锁

消费者生产者问题

package com.java.demo;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo4  {

    /**
     * 澶氱嚎绋嬮€氫俊闂, 鐢熶骇鑰呬笌娑堣垂鑰呴棶棰?
     * @param args
     */
    public static void main(String[] args) {
        Food f = new Food();
        new Cook(f).start();
        new Waiter(f).start();
    }

    //鍘ㄥ笀
    static class Cook extends Thread{
        private Food f;
        public Cook(Food f) {
            this.f = f;
        }

        @Override
        public void run() {
            for(int i=0;i<100;i++){
                if(i%2==0){
                    f.setNameAndSaste("鑰佸共濡堝皬绫崇播","棣欒荆鍛?);
                }else{
                    f.setNameAndSaste("鐓庨ゼ鏋滃瓙","鐢滆荆鍛?);
                }
            }
        }
    }
    //鏈嶅姟鐢?
    static class Waiter extends Thread{
        private Food f;
        public Waiter(Food f) {
            this.f = f;
        }
        @Override
        public void run() {
            for(int i=0;i<100;i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                f.get();
            }
        }
    }
    //椋熺墿
    static class Food{
        private String name;
        private String taste;

        //true 琛ㄧず鍙互鐢熶骇
        private boolean flag = true;

        public synchronized void setNameAndSaste(String name,String taste){
            if(flag) {
                this.name = name;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.taste = taste;
                flag = false;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public synchronized void get(){
            if(!flag) {
                System.out.println("鏈嶅姟鍛樼璧扮殑鑿滅殑鍚嶇О鏄?" + name + ",鍛抽亾:" + taste);
                flag = true;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

第三种实现多线程方法:Callable

package com.lyq.kaikeba.codeLearn.threadLearn;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo5 {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Callable<Integer> c = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(c);
        new Thread(task).start();

        // 使用get方法后主线程会等子线程执行完再执行
        Integer j = task.get();
        System.out.println("返回值为:"+j);
        Thread.sleep(100);
        for(int i=0;i<10;i++){
            System.out.println(i);
        }
    }

    static class MyCallable implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            Thread.sleep(100);
            for(int i=0;i<10;i++){
                System.out.println(i);
            }
            return 100;
        }
    }
}

线程池

频繁地创建和销毁线程需要时间,线程池可以节省这部分时间。

  1. 缓存线程池

长度无限制,  
执行流程:  
    1. 判断线程池是否存在空闲  
    2. 存在则使用  
    3. 不存在,则创建线程并放入线程池,然后使用

package com.lyq.kaikeba.codeLearn.threadLearn;

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

public class Demo6 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        // 向线程池中添加任务
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
            }
        });

        Thread.sleep(1000);
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
            }
        });
    }
}

  1. 定长线程池

长度指定  
执行流程:  
    1. 判断线程池是否满了  
    2. 存在则使用  
    3. 不存在空闲线程,线程池未满则创建线程,并放入线程池,然后使用  
    4. 不存在空闲线程,线程池满了,则等待空闲线程

package com.lyq.kaikeba.codeLearn.threadLearn;

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

/**
 * 定长线程池
 */
public class Demo7 {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

  1. 单线程池

线程空闲则使用,不空闲则等待

package com.lyq.kaikeba.codeLearn.threadLearn;

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

public class Demo8 {
    public static void main(String[] args) {
        ExecutorService service = Executors.newSingleThreadExecutor();

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"test");
            }
        });
    }
}

  1. 周期性任务定长线程池

在定长线程池的基础上,定时执行,当某个时机触发时,自动执行某任务

package com.lyq.kaikeba.codeLearn.threadLearn;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Demo9 {
    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);


        /**
         * 定时执行一次
         * 参数1 : 定时执行的任务
         * 餐数2 : 延迟时间
         * 参数3 : 时间单位, 通过TimeUnit指定常量
         */
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("test");
            }
        }, 5, TimeUnit.SECONDS);


        /**
         * 周期性执行
         * 参数1: 任务
         * 参数2: 延迟执行时间(第一次多久之后执行)
         * 参数3: 执行间隔时间
         * 参数4: 时间单位
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("test1");
            }
        },5,1,TimeUnit.SECONDS);
    }
}

Lambda表达式

package com.lyq.kaikeba.codeLearn.threadLearn;

/**
 * Lambda表达式
 */
public class Demo10 {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("Lambda表达式测试")).start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值