先上图,有点长,比较碎,有xmind文件......,详细内容均在图片里介绍了,提供了PDF文件
1.线程简介
进程是操作系统中正在执行的不同的应用程序,例如:我们可以同时打开Word和记事本
线程是一个应用程序进程中不同的执行路径。进程是不活泼的。进程从来不执行任何东西,它只是线程的容器。线程总是在某个进程环境中创建的,而且它的整个寿命期都在该进程中。
进程是线程的容器。一个进程可以有多个线程,至少有一个线程。而一个线程只能在一个进程的地址空间活动
2.多线程的三种实现方式
3.线程常用方法
3.1.Thread
//Thread
public class MyThread extends Thread{@Overridepublic void run(){for (int i = 0; i < 10; i++) {System.out.println(getName() + "run方法里的函数");}}}
//创建开启线程
public abstract class ThreadDemo {public static void main(String[] args) {// 创建 MyThread 类的实例MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("线程1");t2.setName("线程2");// 启动线程t1.start();t2.start();}
}
3.2.Runnable
//Runnable
public class MyRunnable implements Runnable {@Overridepublic void run() {//获取当前线程的对象Thread thread = Thread.currentThread();System.out.println(thread.getName() + "MyRunnable.run方法实列");}
}//创建开启线程
public class ThreadDemo {public static void main(String[] args) {/** 多线程的第二中启动方式:* 1.自己定义一个类实现Runnable方法* 2.重写里面的run方法* 3.创建自己的类的对象* 4.创建一个Thread类的对象,并开启线程* */MyRunnable myRunnable = new MyRunnable();Thread thread1 = new Thread(myRunnable);Thread thread2 = new Thread(myRunnable);thread1.setName("线程1");thread2.setName("线程2");thread1.start();thread2.start();}
}
3.3.Callable
//Callable
public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {return 100;}
}
//第三种方式
public class ThreadDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {/**多线程的第三种是实现方式* 特点:可以获取到多线程运行的结果* 1、创建一个类MyCallable实现Callable接口* 2、重写call方法(有返回值的,表示多线程运行的结果)* 3、创建MyCallable的对象(表示多线程要执行的任务)* 4、创建FutureTalk的对象(作用是管理多线程运行的结果)* 5、创建Thread类的对象,并启动(表示线程)* *///创建MyCallable的对象(表示多线程要执行的任务)MyCallable myCallable = new MyCallable();//创建FutureTalk的对象(作用是管理多线程运行的结果FutureTask<Integer> futureTask = new FutureTask<>(myCallable);//创建对象Thread thread = new Thread(futureTask);//启动线程thread.start();//获取多线程运行的结果Integer i = futureTask.get();System.out.println(i);}
}
4.锁
锁是一种同步机制,可以用来协调多个线程的并发访问,以保证对共享资源的安全访问。可以理解为防止一件东西同时被多个人使用。用于保护线程安全的一种机制。
4.1.synchronized锁
static int ticket = 0;@Overridepublic void run() {while (true) {synchronized (MyThread.class) {if (method()) break;}}}private synchronized boolean method() {if (ticket < 99){try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}ticket++;System.out.println(Thread.currentThread().getName() + "正在卖第 " + ticket + "票!");}else{return true;}return false;}
4.2.lock锁
public class MyThread extends Thread {static int ticket = 100;static Lock lock = new ReentrantLock();@Overridepublic void run() {/** Lock实现提供比使用sunchronized方法和语句更广泛的锁定操作* lock中提供了获得锁和释放锁的方法* void lock():获得锁* void unlock():释放锁** Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化* ReentrantLock的构造方法** ReentrantLock():创建一个ReentrantLock的实例** */while (true) {//同步代码块,lock上锁lock.lock();if (ticket == 100){break;}else {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}finally {//释放锁lock.unlock();}ticket++;System.out.println(Thread.currentThread().getName() + "在卖第" + ticket);}}}
}
4.3.死锁
详细介绍可看开头的图片
5.生产者和消费者问题
5.1.线程的等待和唤醒
public class Desk {/** 控制生产者和消费者的执行* *///是否有面条 0:没有 1:有public static int foodFlag = 0;//总个数public static int count =10;//锁对象public static Object lock = new Object();
}//消费者
public class Cook extends Thread {/** 消费者* */@Overridepublic void run() {while (true) {synchronized (Desk.lock){if(Desk.count == 0){break;}else{//判断桌子上是否有食物//如果有就等待,没有就唤醒if(Desk.foodFlag == 1){try {//等待Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else{System.out.println("厨师做了一碗面条");//修改桌子状态Desk.foodFlag = 1;//唤醒Desk.lock.notifyAll();}}}}}
}
//生产者
public class Foodie extends Thread {/*生产者* */@Overridepublic void run() {/** 1.循环* 2.同步代码块* 3.判断共享数据是否到了末尾(到了末尾)* 4.判断共享数据是否到了末尾(没有到达末尾,执行核心逻辑)** */while (true) {synchronized (Desk.lock){//先判断桌子上是否有面条if(Desk.count == 0){break;}else{if(Desk.foodFlag == 0){//如果没有try {Desk.lock.wait();//让当前线程和锁进行绑定} catch (InterruptedException e) {throw new RuntimeException(e);}}else{//把吃的总数-1Desk.count--;//如果有就开吃System.out.println(Desk.count + "碗!!!");//吃完之后,唤醒厨师继续做Desk.lock.notifyAll();//修改桌子的状态Desk.foodFlag = 0;}}}}}
}
5.2.阻塞队列
public class ThreadDemo {public static void main(String[] args) {/** 阻塞队列的继承结构* 接口:Iterable* Collection* Queue* BlockingQueue* 实现类L:ArrayBlocking : 数组 ,有界* LinkedBlockingQueue:底层是链表,无界,但不是真正的无界,最大为int的最大值+** */ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);Cook cook = new Cook(queue);Foodie foodie = new Foodie(queue);cook.start();foodie.start();}
}
6.线程池
线程池是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。
6.1.ExecutorService
public class MyThreadPoolDemo {public static void main(String[] args) {/*public static ExecutorService newCachedThreadPool() 创建一个没有上限的线程池public static ExecutorService newFixedThreadPool(int nThread) 创建有上限的线程池*///1.获取线程池对象,池子本身是空的,提交任务的时,池子会创建新的线程对象,// 任务执行完毕,线程归回给池子,下回再次提交任务时,不需要创建新的线程,直接复用已有的线程ExecutorService pool = Executors.newCachedThreadPool();ExecutorService pool1 = Executors.newFixedThreadPool(3);//提交任务pool.submit(new MyRunnable());pool.submit(new MyRunnable());//销毁线程池pool.shutdown();}
6.2.ThreadPoolExecutor
public class ThreadPool {public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,6,60,TimeUnit.SECONDS,new ArrayBlockingQueue<>(2),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());threadPoolExecutor.submit(new MyRunnable());}
}