Java创建多线程的3种方式和Java当中的线程池【杭州多测师】【杭州多测师_王sir】
/**
* 创建线程的3种方式
* 1.继承Thread类
* 2.实现Runnable接口
* 3.实现Callable接口
* 4.一个进程可以有多个线程、一个线程对应一个进程
* 5.防止多线程数据共享和超卖 ==》可以加锁、或者加同步代码块==》synchronized (this)
*/
package com.duoceshi.thread; public class RunningMan extends Thread{ private String name; public RunningMan(String name){ //创建一个构造函数 this.name = name; //初始化 } //重写Thread类里面的run方法==》用Ctrl+alt+空格键 @Override public void run() { for (int i = 0; i <100 ; i++) { System.out.println(this.name + " run " +i+" m"); } } }
package com.duoceshi.thread; public class RunningWoman implements Runnable { private String name; public RunningWoman(String name){ this.name = name; } //RunningWoman实现Runnable接口、需要实现接口里面的抽象方法 public void run() { for(int i=0;i<100;i++){ System.out.println(this.name + " run " + i + " m"); } } }
package com.duoceshi.thread; /** * 创建线程的3种方式 * 1.继承Thread类 * 2.实现Runnable接口 * 3.实现Callable接口 * 4.一个进程可以有多个线程、一个线程对应一个进程 * 5.防止多线程数据共享和超卖 ==》可以加锁、或者加同步代码块==》synchronized (this) */ public class ThreadTest{ public static void main(String[] args) { ThreadTest threadTest = new ThreadTest(); // threadTest.threadTest(); threadTest.runnableTest(); } public void threadTest(){ //创建了3个线程 RunningMan runningMan1 = new RunningMan("博尔特"); RunningMan runningMan2 = new RunningMan("刘翔"); RunningMan runningMan3 = new RunningMan("苏炳添"); runningMan1.start(); //谁先说后看CPU的随机性 runningMan2.start(); runningMan3.start(); } public void runnableTest(){ /** * 把RunningWoman的匿名对象作为Thread类的构造函数的参数传入进来 * 实现Runnable接口优点就是:避免了单继承的局限性、在定义线程的时候建议使用此种方式 */ Thread threadA = new Thread(new RunningWoman("博尔特")); Thread threadB = new Thread(new RunningWoman("刘翔")); Thread threadC = new Thread(new RunningWoman("苏炳添")); threadA.start(); threadB.start(); threadC.start(); } }
package com.duoceshi.thread; /** * 开发一个简单的卖票程序、可以实现多个窗口卖票 * 创建3个线程同时购票 */ public class Ticket implements Runnable{ private int ticketNum = 100; //定义100张火车票 票的库存 /** * 用这种方法有一个问题就是:在线程1购买票的时候CPU已经完成切换去处理线程2购票了 * 然后如此循环导致还没有做ticketNum减票的操作、这样会导致线程之间会共享一份数据 * 所以针对这种情况需要进行加锁、或者加入同步代码块 */ // public void run() { // while (true){ // try { // Thread.sleep(100L); // } catch (InterruptedException e) { // e.printStackTrace(); // } // if(ticketNum<=0){ // break; // } // System.out.println(Thread.currentThread()+"购票后还剩余"+ticketNum); // ticketNum --; // } // } public void run() { while (true){ try { Thread.sleep(100L); } catch (InterruptedException e) { e.printStackTrace(); } //this表示当前的对象、加锁是为了线程安全当上个线程还没结束的时候先跑完上个线程 //再跑接下来的线程 synchronized (this){ if(ticketNum<=0){ break; } System.out.println(Thread.currentThread().getName()+"卖票、还剩余票数为:"+ticketNum); ticketNum --; } } } }
package com.duoceshi.thread; public class TicketTest { public static void main(String[] args) { //创建一个对象、3个线程共享 Ticket ticket = new Ticket(); Thread thread1 = new Thread(ticket); Thread thread2 = new Thread(ticket); Thread thread3 = new Thread(ticket); thread1.start(); thread2.start(); thread3.start(); } }
线程池
Java 语言虽然内置了多线程支持,启动一个新线程非常方便,但是,创建线程需要操作系统资源(线程资源,栈空间等),频繁创建和销毁大量线程需要消耗大量时间。
线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
简单地说,线程池内部维护了若干个线程,没有任务的时候,这些线程都处于等待状态。如果有新任务,就分配一个空闲线程执行。如果所有线程都处于忙碌状态,新任务要么放入队列等待,要么增加一
个新线程进行处理。
四种线程池
Java 通过 Executors 接口提供四种线程池,分别为:
1、 newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序( FIFO , LIFO ,优先级)行。
2、 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3、newScheduledThreadPool 创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
4、 newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程池
package com.duoceshi.thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * author:杭州滨江多测师_王sir */ public class ThreadPool{ public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 10 ; i++) { RunningWoman runningWoman = new RunningWoman("翠花"+i); executorService.submit(runningWoman); } //关闭线程池 executorService.shutdown(); } }