java实现多线程?多线程详解

Thread

通过创建类继承Thread类,实现多线程

package com.java;

public class Demo01 {
    public static void main(String[] args) {
        MyThread m = new MyThread();
        m.start();
        for(int i=0;i<10;i++){
            System.out.println("汗滴禾下土"+i);
        }
    }
    static class Mythread extends Thread {
    	/**
     * run方法就是线程要执行的任务方法
     */
    @Override
    public void run() {
        //这里的代码 就是一条新的执行路径
        //这个执行路径的触发方式,不是调用run方法,而是通过Thread对象的start方法
        for(int i = 0;i<10;i++){
            System.out.println("锄禾日当午"+i);
        }
    }
    }
}
/*
汗滴禾下土0
锄禾日当午0
汗滴禾下土1
汗滴禾下土2
汗滴禾下土3
锄禾日当午1
汗滴禾下土4
锄禾日当午2
汗滴禾下土5
锄禾日当午3
汗滴禾下土6
锄禾日当午4
汗滴禾下土7
锄禾日当午5
汗滴禾下土8
锄禾日当午6
汗滴禾下土9
锄禾日当午7
锄禾日当午8
锄禾日当午9
*/

Runnable

Runnable属于接口类

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

package com.java;

public class Demo02 {
    /**
     * 多线程技术
     * 实现Runnable 与 继承Thread相比有如下优势:
     * 1.   通过创建任务,然后给线程分配的方式来实现的多线程,更适合多个线程同时执行相同任务的情况
     * 2.   可以避免单继承所带来的局限性
     * 3.   任务与线程本身是分离的,提高了程序的健壮性
     * 4.   后续学习的线程池技术,接受Runnable类型的任务,不接收Thread类型的线程
     * @param args
     */
    public static void main(String[] args) {
        //实现Runnable
        MyRunnable r = new MyRunnable();
        //1.    创建一个任务对象
        //为线程定义名称
        Thread t = new Thread(r,"线程1");
        //2。    创建一个线程,并为其分配一个任务
        t.start();
        //获取子线程名称
        System.out.println(t.getName());
        //获取当前主线程的名称
        System.out.println(Thread.currentThread().getName());

    }
    static class MyRunnable implements Runnable{
    	@Override
	    public void run() {
	        //线程的任务
	        for(int i=0;i<10;i++){
	            System.out.println("床前明月光"+i);
	        }
	    }
	}
}
/*
线程1
main
床前明月光0
床前明月光1
床前明月光2
床前明月光3
床前明月光4
床前明月光5
床前明月光6
床前明月光7
床前明月光8
床前明月光9
*/

线程中断

代码实现如下:

package com.java;

public class Demo05 {
    public static void main(String[] args) {
        //线程中断
        //一个线程是一个独立的执行结构,他是否应该结束,应该由其自身决定
        MyRunnable m = new MyRunnable();
        Thread t = new Thread(m);
        t.start();
        for(int i=0;i<5;i++){
            //获取当前线程的名称
            System.out.println(Thread.currentThread().getName()+":"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //给线程添加中断“标记”,当发现标记时,run方法就会抛出异常,进入catch块
        t.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) {
                    //发现标记后进入到这里,线程还不会立即中断,必须使用1return方法
                    System.out.println("发现了标记,利用return自杀");
                    //通过使用return结束run方法,来结束该线程
                    return;
                }
            }
        }
    }
}

线程休眠

通过使用Thread类下的sleep方法可以实现线程休眠

package com.java;

public class Demo03 {
    /**
     * 多线程技术
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        //线程休眠技术 sleep
        for(int i=0;i<10;i++){
            Thread.sleep(2000);
            System.out.println(i);
        }

    }
}
/*
Thread-0:0
main:0
Thread-0:1
main:1
main:2
Thread-0:2
Thread-0:3
main:3
Thread-0:4
main:4
Thread-0:5
发现了标记,利用return自杀
*/

守护线程

线程:分为守护线程和用户线程
用户线程:当一个进程不包含任何的存活的用户线程时,进行结束
守护线程:守护用户线程,当最后一个线程结束时,所有守护线程自动死亡

代码实现案例:

package com.java;

public class Demo06 {
    public static void main(String[] args) {
        //线程:分为守护线程和用户线程
        //用户线程:当一个进程不包含任何的存活的用户线程时,进行结束
        //守护线程:守护用户线程,当最后一个线程结束时,所有守护线程自动死亡
        Thread t = new Thread(new MyRunnable());
        //设置t为守护线程
        t.setDaemon(true);
        t.start();
        for(int i=0;i<5;i++){
            //获取当前线程的名称
            System.out.println(Thread.currentThread().getName()+":"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //主线程结束,守护线程t结束
    }

    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自杀");
                    //通过使用return结束run方法,来结束该线程
                    return;
                }
            }
        }
    }
}
//运行结果,主线程结束时,守护线程自动结束
/*
main:0
Thread-0:0
Thread-0:1
main:1
Thread-0:2
main:2
Thread-0:3
main:3
Thread-0:4
main:4
Thread-0:5
*/

线程不安全

代码实现案例:

package com.java;

public class Demo07 {
    /**
     * 线程不安全问题
     * @param args
     */
    public static void main(String[] args) {
        Ticket run = new Ticket();
        //同时使用三个线程去执行
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable {
        //票数
        private int count=4;
        @Override
        public void run() {
            while (count > 0) {
                System.out.println("正在卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println("出票成功,余票:" + count);
            }
        }
    }
}
//运行结果,票数中存在负票数
/*
正在卖票
正在卖票
正在卖票
出票成功,余票:3
正在卖票
出票成功,余票:3
正在卖票
出票成功,余票:3
正在卖票
出票成功,余票:2
正在卖票
出票成功,余票:1
正在卖票
出票成功,余票:2
正在卖票
出票成功,余票:0
出票成功,余票:-1
出票成功,余票:0
*/

1. 同步代码块

同步代码块(锁机制),三个线程不能同时执行该代码块

package com.java;

public class Demo08 {
    /**
     * 线程不安全问题
     * 解决方案1:同步代码块
     * @param args
     */
    public static void main(String[] args) {
        Ticket run = new Ticket();
        //同时使用三个线程去执行
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket 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(Thread.currentThread().getName() + "正在卖票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println("出票成功,余票:" + count);
                    } else {
                        break;
                    }
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//运行结果
/*
Thread-0正在卖票
出票成功,余票:9
Thread-2正在卖票
出票成功,余票:8
Thread-1正在卖票
出票成功,余票:7
Thread-2正在卖票
出票成功,余票:6
Thread-0正在卖票
出票成功,余票:5
Thread-2正在卖票
出票成功,余票:4
Thread-1正在卖票
出票成功,余票:3
Thread-2正在卖票
出票成功,余票:2
Thread-0正在卖票
出票成功,余票:1
Thread-2正在卖票
出票成功,余票:0
*/

2. 同步方法

package com.java;

public class Demo09 {
    /**
     * 线程不安全问题
     * 解决方案2:同步方法
     * @param args
     */
    public static void main(String[] args) {
        Ticket run = new Ticket();
        //同时使用三个线程去执行
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable {
        //票数
        private int count=10;
        private Object o = new Object();
        @Override
        public void run() {
            //同步代码块(锁机制),三个线程不能同时执行该代码块
            while (true) {
                boolean flag = sale();
                if(!flag){
                    break;
                }
            }
        }
        //被synchronized修饰的方法为同步方法,线程需排队执行
        public synchronized boolean sale() {
            if (count > 0) {
                System.out.println(Thread.currentThread().getName() + "正在卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println("出票成功,余票:" + count);
                return true;
            }
            return false;
        }

    }
}

3. 显示锁

package com.java;

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

public class Demo10 {
    /**
     * 同步代码块 和 同步方法 都属于隐式锁
     * 解决方案3:显示锁 lock 子类 ReentrantLock
     * @param args
     */
    public static void main(String[] args) {
        Ticket run = new Ticket();
        //同时使用三个线程去执行
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable {
        //票数
        private int count=10;
        //显示锁 l : fair参数为true 就是公平锁(谁先来谁先得到锁)
        private Lock l = new ReentrantLock(true);
        @Override
        public void run() {
            //同步代码块(锁机制),三个线程不能同时执行该代码块
            while (true) {
                //上锁
                l.lock();
                if (count > 0) {
                    System.out.println(Thread.currentThread().getName() + "正在卖票");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count--;
                    System.out.println("出票成功,余票:" + count);
                }else {
                    break;
                }
                //解锁
                l.unlock();
            }
        }
    }
}

线程池 Executor

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

线程池的好处

  • 降低资源消耗
  • 提高响应速度
  • 提高线程的可管理性

Java中的四种线程池

1. 缓存线程池

长度的无限制

执行流程:

  1. 判断线程池是否存在空闲线程
    1. 存在则使用
      1. 不存在则创建线程,并放入线程池,然后使用
package com.java;

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

public class Demo11 {
    /**
     * 缓存线程池.
     * (长度无限制)
     * 执行流程:
     * 1. 判断线程池是否存在空闲线程
     * 2. 存在则使用
     * 3. 不存在,则创建线程 并放入线程池, 然后使用
     */
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
//向线程池中 加入 新的任务
        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());
            }
        });
        //让主线程休眠 1 秒
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //此时上面有三个空闲的线程,随机调用一个进行使用
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程的名称:"+Thread.currentThread().getName());
            }
        });
    }

}

//运行结果
/*
    线程的名称:pool-1-thread-1
    线程的名称:pool-1-thread-2
    线程的名称:pool-1-thread-3
    线程的名称:pool-1-thread-1
*/

2. 定长线程池

长度是指定的数值

任务加入后的执行流程:

  1. 判断线程池是否存在空闲线程
    1. 存在则使用
      1. 不存在空闲线程,且线程池未满的情况下,则创建线程并放入线程池,然后使用
      2. 不存在空闲线程,且线程已满的情况下,则等待线程池存在的空闲线程
package com.java;

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

public class Demo12 {
    /**
     * 定长线程池.
     * (长度是指定的数值)
     * 执行流程:
     * 1. 判断线程池是否存在空闲线程
     * 2. 存在则使用
     * 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
     * 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
     */
    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());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程的名称:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //已经在线程池中创建了两个线程,该线程需要等待3s后才会出现空闲线程,然后使用
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程的名称:"+Thread.currentThread().getName());
            }
        });
    }
}
/*
线程的名称:pool-1-thread-1
线程的名称:pool-1-thread-2
线程的名称:pool-1-thread-1
*/

3. 单线程线程池

执行流程:

  1. 判断线程池的 哪个线程 是否空闲
    1. 空闲则使用
      1. 不空闲,则等待池中的单个线程空闲后使用
package com.java;

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

public class Demo13 {
    public static void main(String[] args) {
        /**
         * 单线程线程池.
         * 执行流程:
         * 1. 判断线程池 的那个线程 是否空闲
         * 2. 空闲则使用
         * 4. 不空闲,则等待 池中的单个线程空闲后 使用
         */
        ExecutorService service = Executors.newSingleThreadExecutor();
        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-1
*/

4. 周期定长线程池

周期任务 定长线程池、

执行流程:

  1. 判断线程池是否存在空闲线程
  2. 存在则使用
  3. 不存在空闲线程,且线程未满的情况下,则创建线程并放入线程池,然后使用
  4. 不存在空闲线程,且线程已满的情况下,则等待线程池存在空闲线程

周期性任务执行时:

定期执行,当某个实际出发时,自动执行某任务
package com.java;

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

public class Demo14 {
    public static void main(String[] args) {
        /**
         * 周期任务 定长线程池.
         * 执行流程:
         * 1. 判断线程池是否存在空闲线程
         * 2. 存在则使用
         * 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
         * 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
         *
         * 周期性任务执行时:
         * 定时执行, 当某个时机触发时, 自动执行某任务 .
        */
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
        /**
         * 定时执行
         * 参数1. runnable类型的任务
         * 参数2. 时长数字
         * 参数3. 时长数字的单位
         */
        service.schedule(new Runnable() {
        @Override
        public void run() {
        System.out.println("俩人相视一笑");
        }
        },5, TimeUnit.SECONDS);
        /**
         * 周期执行
         * 参数1. runnable类型的任务
         * 参数2. 时长数字(延迟执行的时长)
         * 参数3. 周期时长(每次执行的间隔时间)
         * 参数4. 时长数字的单位
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("嘿嘿嘿");
            }
        },5,2,TimeUnit.SECONDS);
    }
}
/*
嘿嘿嘿
俩人相视一笑
嘿嘿嘿
嘿嘿嘿
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值