多线程的基本使用

一,多线程

1.多线程技术概述

1.1 线程与进程

进程:
	1-是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间
	
线程:
	1-是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少与一个线程
	2-线程实际上是在线程基础上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程

1.2 线程调度

分时调度:
	-所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
抢占式调度:
	1-优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),java使用的就是抢占式调度。
	2-CPU使用抢占式调度模式在

1.3 同步与异步

同步:排队执行,效率低但是安全。
异步:同时执行,效率高但是数据不安全。

1.4 并发与并行

并发:指两个或多个事件在同一个时间段发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。

1.5 执行过程图

在这里插入图片描述

在这里插入图片描述

注意
每一个线程都拥有自己的栈空间,但共用一份堆内存。
由一个线程执行的方法,那么这个方法也会执行在这个线程里面,也就是说也会在这个线程的栈内存里面执行。

1.6 线程阻塞(也就是耗时操作)

2.Thread(此类就是一个线程)

2.1 直接继承来实现多线程

public class Thread_1 {
    public static void main(String[] args) {
        MaThread maThread=new MaThread();
        maThread.start();//通过start来启动这个线程
        for (int i = 0; i < 10; i++) {
            System.out.println("我是main线程"+i);
        }
    }
}
class MaThread extends Thread{
    @Override
    public void run() {//run方法就是线程要执行的方法
        //这里的代码就是一个新的执行路径,且调用这个方法不能直接调用run方法
        for (int i = 0; i < 10; i++) {
            System.out.println("我是新的线程"+i);
        }
    }
}

2.2 匿名内部类实现多线程(也是继承关系)

public class Thread_2 {
    public static void main(String[] args) {
        new Thread(){//匿名内部类必须继承一个父类或则实现一个接口
            //这就是继承了Thread()类
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("我是新的线程"+i);
                }
            }
        }.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("我是旧的线程"+i);
        }
    }
}

3.Runnable (创建任务)

3.1 案列实现

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

        MyRunnable maThread= new MyRunnable();
        Thread t=new Thread(maThread);
        t.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("我是新的线程"+i);
        }
    }
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("我是旧的线程"+i);
        }
    }
}

4. 使用Runnable的优点(与Thread比)

 Runnable是通过创建任务,然后给线程分配任务,
 
 1,更适合多个线程同时执行相同任务的情况,并且可以避免单继承带来的局限性
 
 2.任务与线程本身是分离的,提高了程序的健壮性。
 
 3.后续学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程

5. 设置并获取线程的名称

Thread.currentThread().getName()//获取当前线程的名称
new Thread(线程任务对象,"新设置的名称").start();//设置线程名称并启动

6. 线程休眠sleep

sleep()方法是是Tread的静态方法,可以直接调用。
即:Tread.sleep(毫秒);

7. 线程的中断

一个线程是独立的执行路径,它是否结束应该由自身决定。
我们应该给线程一个标记,然后当遇到标记时,直接创建一个新的异常进入catch语句中,线程是否结束由catch中的语句决定

如:public class interrupt_1 {
    public static void main(String[] args) {
        Thread t1=new Thread(new MyRunnable2(),"子线程");
        t1.start();
        for (int i = 1; i <= 5; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        t1.interrupt();//给线程一个标记,当线程运到这个位置时,产生一个新的异常,然后直接进去catch
    }
    static class MyRunnable2 implements Runnable{
        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //e.printStackTrace();
                    System.out.println("发现了中断标记,我们这个线程自动死亡");
                    return;//结束这个任务
                }
            }
        }
    }
}

8. 守护线程和用户线程

线程分为守护线程和用户线程
用户线程:当一个线程不包含任何的守护线程时,这个线程结束。
守护线程:守护用户线程的,当用户线程全部死亡,守护线程自动死亡

Thread t1=new Thread(new MyRunnable());
t1.setDaemon(true);//true表示是守护线程
t1.start();

注意:设置守护线程应该在启动线程之前

二,线程安全

1.线程安全1,同步代码块(隐式锁)

  三个对象同时抢对象o这把锁,谁先抢到锁o,谁先执行,其余线程等待,直到抢到锁的线程执行结束,然后又重新开始抢
  注意:谁先抢到第一把锁的线程,抢到第二把的机会就更高(这就叫回首掏)

public class synchronized_1 {
    public static void main(String[] args) {
        Runnable run=new MyRunnable();
        new Thread(run,"一").start();
        new Thread(run,"二").start();
        new Thread(run,"三").start();
    }
    static class MyRunnable implements Runnable{
        private int count=10;
        Object o=new Object();
        @Override
        public void run() {
            while (true){
                synchronized (o){
                    if(count>0){
                        System.out.println("正在出票");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName()+"出票成功,剩余票数"+count);
                    }else {
                        break;
                    }
                }
            }
        }
    }
}

2. 线程安全2-同步方法(隐式锁)

注意:同步方法上锁的是this,这个this就是调用这个方法的对象,在这里就是run对象
如果这个方法是静态的,那么上锁的就是方法类的.class
public class synchronized_2 {
    public static void main(String[] args) {
        Runnable run=new synchronized_1.MyRunnable();
        new Thread(run,"一").start();
        new Thread(run,"二").start();
        new Thread(run,"三").start();
    }
    static class MyRunnable implements Runnable{

        @Override
        public void run() {
            while (true){
                Boolean aa=say();
                if (aa=false){
                    break;
                }
            }
        }
        public synchronized  Boolean say(){
            int count=10;
            if (count>0){
                System.out.println("正在出票");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"出票成功,剩余票数"+count);
            }
            return false;
        }
    }
}

3. 线程安全3-显示锁Lock

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

public class Lock_1 {
    public static void main(String[] args) {
        Runnable myLock=new MyLock();
        new Thread(myLock).start();
        new Thread(myLock).start();
        new Thread(myLock).start();
    }
}
class MyLock implements Runnable{
    int count=10;
    //创建一个锁
    Lock l=new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            l.lock();//开始锁住
            if (count > 0) {
                System.out.println("正在出票");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName() + "出票成功,剩余票数" + count);

            } else if (count==0){
                break;
            }
            l.unlock();//解锁
        }
    }
}

三, 带返回值得线程Callable

public class Callable1 {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Callable<Integer> ca=new MyCallable();//创建对象
        FutureTask<Integer> fu=new FutureTask<>(ca);//创建任务
        new Thread(fu).start();//创建线程运行任务
        fu.get();//主线程停在这里等子线程执行完毕
        for (int i = 0; i < 10; i++) {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"我运行"+i+"次");
        }
    }
    static public class MyCallable implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+"我运行"+i+"次");
            }
            return 100;
        }
    }
}

四, 线程池

 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程 就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容 器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。 

1.线程池的好处

1-降低资源消耗
2-提高响应速度
3-提高线程的可管理性

2.Java中的四种线程池 . ExecutorServic

2.1 缓存线程池

public class newCachedThreadPool {
    public static void main(String[] args) {
        ExecutorService service= Executors.newCachedThreadPool();//新建一个缓存线程池
        //指挥线程池执行新的任务,以下是3个线程执行三个任务
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘻嘻");
            }
        });   service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘿嘿");
            }
        });   service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"哈哈");
            }
        });
    }
}
结果:pool-1-thread-1嘻嘻
	pool-1-thread-3哈哈
	pool-1-thread-2嘿嘿

2.2 定长度线程池

public class newFixedThreadPool {
    public static void main(String[] args) {
        ExecutorService service= Executors.newFixedThreadPool(2);//定长度线程池,把线程池的个数定位2
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘻嘻");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘿嘿");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });service.execute(new Runnable() {//因为线程池中线程的个数为2,所以第三个线程只有等其中一个结束,才能执行
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"哈哈");
            }
        });
    }
}
结果:
pool-1-thread-1嘻嘻
pool-1-thread-2嘿嘿
pool-1-thread-1哈哈

2.3 单线程线程池

public class newSingleThreadPool {
    public static void main(String[] args) {
        ExecutorService service= Executors.newSingleThreadExecutor();
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘻嘻");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘿嘿");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });service.execute(new Runnable() {//因为线程池中线程的个数为2,所以第三个线程只有等其中一个结束,才能执行
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"哈哈");
                return;
            }
        });
    }
}
结果:
pool-1-thread-1嘻嘻
pool-1-thread-1嘿嘿
pool-1-thread-1哈哈

2.4 周期定长线程池

//周期定长线程池
public class newScheduledThreadPool {
    public static void main(String[] args) {
        ScheduledExecutorService service= Executors.newScheduledThreadPool(2);
        /**
         * 1 定时执行一次
         * 参数1:定时执行的任务
         * 参数2:时长数字
         * 参数3:时长数字的时间单位,TimeUnit的常量指定
         */
        /*service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘿嘿");
            }
        },4, TimeUnit.SECONDS);//4秒后执行*/

        /**
         * 2 周期执行任务
         * 参数1:任务
         * 参数2:延迟时长数字(第一次在什么时间以后)
         * 参数3:周期时长数字(每隔多久执行一次)
         * 参数4:时长数字单位
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"嘿嘿");
            }
        },4,2,TimeUnit.SECONDS);
    }
}

五, Lambda表达式

Lambda表达式相当于直接使用方法,不要对象
一个接口只有一个抽象方法才能使用Lambda表达式
public static void main(String[] args) {
        /*print(new MyMath() {
            @Override
            public int sun(int x, int y) {
                return x+y;
            }
        },5,3);*/
        print((int x,int y) -> {
            return x+y;
        },1,3);
    }
    public static void print(MyMath m,int x,int y){
        int num=m.sun(x,y);
        System.out.println(num);
    }

   static interface MyMath{
        int sun(int x,int y);
   }
}

Lambda表达式相当于直接使用方法,不要对象
一个接口只有一个抽象方法才能使用Lambda表达式
public static void main(String[] args) {
        /*print(new MyMath() {
            @Override
            public int sun(int x, int y) {
                return x+y;
            }
        },5,3);*/
        print((int x,int y) -> {
            return x+y;
        },1,3);
    }
    public static void print(MyMath m,int x,int y){
        int num=m.sun(x,y);
        System.out.println(num);
    }

   static interface MyMath{
        int sun(int x,int y);
   }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值