一、实现多线程
多线程是为了同步完成多项任务,提高资源使用率提高系统使用率。
1、继承Thread类
void run() | 在线程开启后,此方法将被调用执行,run()封装了被线程执行的代码 |
void start() | 启动线程,Java虚拟机会调用run方法()、即由JVM调用此线程的run()方法 |
public class MultiThreaded extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("继承thread " + i);}}public static void main(String[] args) {MultiThreaded multiThreaded = new MultiThreaded();MultiThreaded multiThreaded1 = new MultiThreaded();multiThreaded.start();multiThreaded1.start();}
}
2、实现Runnable接口
Thread(Runnable target) | 分配一个新的Thread对象 |
Thread(Runnable target, String name) | 分配一个新的Thread对象 |
public class RunnableThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + i);}}public static void main(String[] args) {RunnableThread run = new RunnableThread();//创建Thread类的对象,把RunnableThread对象作为构造方法的参数Thread is = new Thread(run, "is");Thread lunatic = new Thread(run, "lunatic");//启动线程is.start();lunatic.start();}
}
3、实现Callable接口
V call() | 计算结果,如果无法计算结果,则抛出一个异常 |
FutureTask(Callable<V> callable) | 创建一个 FutureTask,一旦运行就执行给定的 Callable |
V get() | 如有必要,等待计算完成,然后获取其结果 |
public class CallableThread implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i < 100; i++) {sum += i;}//返回值就表示线程运行完毕之后的结果return sum;}public static void main(String[] args) throws ExecutionException, InterruptedException {//线程开启之后需要执行里面的call方法CallableThread call = new CallableThread();//可以获取线程执行完毕之后的结果.也可以作为参数传递给Thread对象FutureTask<Integer> task = new FutureTask<>(call);//创建线程对象Thread thread = new Thread(task);//开启线程thread.start();Integer str = task.get();System.out.println("str = " + str);}
}
4、对比
实现 | 好处 | 坏处 |
实现Runnable、Callable接口 | 扩展性强,实现该接口的同时还可以继承其他的类 | 编程相对复杂,不能直接使用Thread类中的方法 |
继承Thread | 编程比较简单,可以直接使用Thread类中的方法 | 可以扩展性较差,不能再继承其他的类 |
5、线程调度
分时调度模型 | 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片 |
抢占式调度模型 | 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些 |
线程优先级:默认优先级是5;设置优先级在1~10之间。
6、线程同步
同步代码块
public class RunnableThread implements Runnable {private int tickets = 100;private Object obj = new Object();@Overridepublic void run() {while (true) {synchronized (obj) { // 对可能有安全问题的代码加锁,多个线程必须使用同一把锁//t1进来后,就会把这段代码给锁起来if (tickets > 0) {try {Thread.sleep(100);//t1休息100毫秒} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--; //tickets = 99;}}//t1出来了,这段代码的锁就被释放了}}public static void main(String[] args) {RunnableThread run = new RunnableThread();//创建Thread类的对象,把RunnableThread对象作为构造方法的参数Thread is = new Thread(run, "is");Thread lunatic = new Thread(run, "lunatic");//启动线程is.start();lunatic.start();}
}
好处 | 解决了多线程数据安全问题 |
坏处 | 当线程有多个,每个线程都会去判断同步上的锁,造成资源耗费严重,降低程序运行效率 |
同步方法
public class TbRunnable implements Runnable{private static int ticketCount = 100;@Overridepublic void run() {while(true){if("is".equals(Thread.currentThread().getName())){//同步方法boolean result = synchronizedMethod();if(result){break;}}if("lunatic".equals(Thread.currentThread().getName())){//同步代码块synchronized (TbRunnable.class){if(ticketCount == 0){break;}else{try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}ticketCount--;System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticketCount + "张票");}}}}}private static synchronized boolean synchronizedMethod() {if(ticketCount == 0){return true;}else{try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}ticketCount--;System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticketCount + "张票");return false;}}public static void main(String[] args) {TbRunnable tb = new TbRunnable();Thread t1 = new Thread(tb);Thread t2 = new Thread(tb);t1.setName("is");t1.setName("lunatic");t1.start();t2.start();}
}
Lock锁:unlock(释放锁)和lock(获得锁)
public class Ticket implements Runnable {//票的数量private int ticket = 100;private Object obj = new Object();private ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {//synchronized (obj){//多个线程必须使用同一把锁.try {lock.lock();if (ticket <= 0) {//卖完了break;} else {Thread.sleep(100);ticket--;System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}// }}}public static void main(String[] args) {Ticket tk = new Ticket();Thread t1 = new Thread(tk);Thread t2 = new Thread(tk);Thread t3 = new Thread(tk);t1.setName("ttt1");t2.setName("ttt2");t3.setName("ttt3");t1.start();t2.start();t3.start();}
}
8、线程池
存放线程的容器
Executors线程池
public class MyThreadPoolDemo {public static void main(String[] args) throws InterruptedException {//1,创建一个默认的线程池对象.池子中默认是空的.默认最多可以容纳int类型的最大值.ExecutorService executorService = Executors.newCachedThreadPool();//Executors --- 可以帮助我们创建线程池对象//ExecutorService --- 可以帮助我们控制线程池executorService.submit(()->{System.out.println(Thread.currentThread().getName() + "在执行了");});Thread.sleep(2000);executorService.submit(()->{System.out.println(Thread.currentThread().getName() + "在执行了");});executorService.shutdown();}
}
ThreadPoolExecutor线程池
corePoolSize | 核心线程的最大值,不能小于0 |
maximumPoolSize | 最大线程数,不能小于等于0,maximumPoolSize >= corePoolSize |
keepAliveTime | 空闲线程最大存活时间,不能小于0 |
unit | 时间单位 |
workQueue | 任务队列,不能为null |
threadFactory | 创建线程工厂,不能为null |
handler | 任务的拒绝策略,不能为null |
public class MyThreadPoolDemo3 {
// 参数一:核心线程数量
// 参数二:最大线程数
// 参数三:空闲线程最大存活时间
// 参数四:时间单位
// 参数五:任务队列
// 参数六:创建线程工厂
// 参数七:任务的拒绝策略public static void main(String[] args) {ThreadPoolExecutor pool = new ThreadPoolExecutor(2,5,2, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());pool.submit(new RunnableThread());pool.submit(new RunnableThread());pool.shutdown();}
}