程序:程序是指令和数据的有序集合,它是静态的,没有运行的含义。
进程:进程就是执行程序的过程,它是动态的。是系统资源分配器的单位。
线程:进程可以分成多个单元同时运行,这些再被进程分配的多个单元叫做线程。线程是cpu调度的最小单位。
进程控制块:控制进程。里面存放进程的信息。
下面是关系图: 实际上,一个CPU,同一时刻只能执行一个线程。但是CPU运算速度很快,达到纳秒级别,我们在宏观上是多个任务同时执行,即并行。
多任务:同时执行多个任务。例如:边做什么边做什么。
多线程:多个线程同时执行。
三种创建线程的方式:继承Thread类、实现Runnable接口、实现Callable接口。
该类实现了Runnable接口。
创建步骤:
自定义一个类继承Thread类重写run方法调用start方法,启动线程。 public class MyThread1 extends Thread { @Override public void run() { for (int i = 0; i < 200; i++) { System.out.println("我是线程1--"+ i); } } public static void main(String[] args) { //创建一个线程对象 MyThread1 myThread1 = new MyThread1(); //开启线程 myThread1.start(); //主线程 for (int i = 0; i < 2000; i++) { System.out.println("我是主线程--" + i); } } }实现步骤:
实现callable接口,需要返回值类型重写call方法,需要抛出异常创建目标对象创建执行服务提交服务获取服务关闭服务图片下载案例:
//线程创建方式3, public class TestCallable implements Callable<Boolean> { private String url; private String name; public TestCallable(String url, String name){ this.url = url; this.name = name; } @Override public Boolean call() { WebDownloader1 webDownloader = new WebDownloader1(); webDownloader.downDownload(url,name); System.out.println("下载文件名:"+name); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { //创建目标对象 TestCallable testThread1 = new TestCallable("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1601280086&di=2572142a87268b8c40db22edb56399d8&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg","1.jpg"); TestCallable testThread2 = new TestCallable("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1601280086&di=2572142a87268b8c40db22edb56399d8&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg","2.jpg"); TestCallable testThread3 = new TestCallable("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1601280086&di=2572142a87268b8c40db22edb56399d8&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg","3.jpg"); //创建执行服务 ExecutorService ser = Executors.newFixedThreadPool(3); //提交执行 Future<Boolean> result1 = ser.submit(testThread1); Future<Boolean> result2 = ser.submit(testThread2); Future<Boolean> result3 = ser.submit(testThread3); //获取结果 boolean rs1 = result1.get(); boolean rs2 = result2.get(); boolean rs3 = result3.get(); System.out.println(rs1+"-"+rs2+"-"+rs3); //关闭服务 ser.shutdownNow(); } } class WebDownloader1{ //下载方法 public void downDownload(String url, String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("io异常"); } } }静态代理模式:
目标对象和代理对象都要实现同一个接口
代理对象要代理目标对象
好处:代理对象可以做目标对象做不了的东西,而目标对象可以只关注自己的事情
结婚代理案例:
public class StaticProxy { public static void main(String[] args) { //委托人 You you =new You(); //代理人 WeddingCompany weddingCompany = new WeddingCompany(you); //执行代理方法 weddingCompany.happyMarry(); } } //结婚接口 interface Marry{ //结婚 void happyMarry(); } //结婚对象 class You implements Marry{ //某人结婚 @Override public void happyMarry() { System.out.println("某人结婚"); } } //婚庆公司 class WeddingCompany implements Marry{ //委托人,代理对象 private Marry target; public WeddingCompany(Marry target) { this.target = target; } //举办婚礼 @Override public void happyMarry() { System.out.println("布置现场"); this.target.happyMarry(); System.out.println("收拾现场"); } }线程的五大状态:创建状态,就绪状态、运行状态、阻塞状态、死亡状态。
休眠案例:
public class TestSleep2 implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("倒计时:"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { //10秒倒计时 new Thread(new TestSleep2()).start(); //获取系统当前时间 Date startTime = new Date(System.currentTimeMillis()); while (true){ try { System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); Thread.sleep(1000); startTime = new Date(System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } } }礼让方法:yield()
线程礼让,让当前执行的线程暂停,但不阻塞
让cpu重新调度,礼让不一定成功
将线程从运行转为就绪状态
用getState()获取当前线程的状态。
Java提供一个线程调度器类监控程序中启动后进入就绪状态的所有线程,线程调度按照优先级决定应该调度哪个线程来执行
线程的优先级用数字表示,范围从1-10
getPriority()和setPriority(int xxx)用来设置和获取优先级
注意:先设置再start。高优先级不一定先调用。
public class TestPriority{ public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+ "->" +Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread thread1 = new Thread(myPriority); Thread thread2 = new Thread(myPriority); Thread thread3 = new Thread(myPriority); Thread thread4 = new Thread(myPriority); Thread thread5 = new Thread(myPriority); Thread thread6 = new Thread(myPriority); thread1.start(); thread2.setPriority(1); thread2.start(); thread3.setPriority(4); thread3.start(); thread4.setPriority(Thread.MAX_PRIORITY); thread4.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+ "->" +Thread.currentThread().getPriority()); } }线程同步:出现在多个线程操作同一个资源。是一种等待机制。
线程同步:sychronized关键字。
并发:同一个对象被多个线程同时操作。
并发问题:
//多个线程同时操作同一个对象 //买火车票 public class TestThread4 implements Runnable{ //票数 private int ticketNums = 10; @Override public void run() { while (ticketNums > 0) { try { //模拟延时 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "线程1拿票第" + ticketNums-- + "票"); } } public static void main(String[] args) { TestThread4 ticket = new TestThread4(); new Thread(ticket,"小明").start(); new Thread(ticket,"小花").start(); new Thread(ticket,"小红").start(); } }执行结果:
小红线程1拿票第10票 小花线程1拿票第9票 小明线程1拿票第10票 小红线程1拿票第8票 小花线程1拿票第8票 小明线程1拿票第7票 小花线程1拿票第6票 小明线程1拿票第4票 小红线程1拿票第5票 小红线程1拿票第3票 小花线程1拿票第1票 小明线程1拿票第2票
sychronized使用:
sychronized方法
在方法用sychronized修饰
public sychronized void buy(){ } //sychronized相当于一把锁,它把这个方法对应的对象锁着,一次只能一个人访问该对象。 //对于上述买车票问题线程同步实现 public sychronized void run() { while (ticketNums > 0) { try { //模拟延时 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "线程1拿票第" + ticketNums-- + "票"); } } //该锁锁的是TestThread4这个对象sychronized块
sychronized(obj){ 实现; } //块锁的是该obj对象,一次只能一个人访问该对象,而不是方法对应的对象。 //将上述买票重新写一下,用锁块实现同步,这个锁的是ticket这个对象 class Ticket{ public int ticketNums = 20; } public class UnsafeBuyTicket implements Runnable{ //票数 private int ticketNums = 10; boolean flag = true; Ticket ticket = new Ticket(); @Override public void run() { //买票 while(flag){ try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } public void buy() throws InterruptedException { synchronized (ticket){ if(ticket.ticketNums <= 0){ this.flag = false; return; } Thread.sleep(100); //买票 System.out.println(Thread.currentThread().getName() + "买到第" + ticket.ticketNums-- +"张票"); } } public static void main(String[] args) { UnsafeBuyTicket unsafeBuyTicket = new UnsafeBuyTicket(); new Thread(unsafeBuyTicket,"小明").start(); new Thread(unsafeBuyTicket,"小华").start(); new Thread(unsafeBuyTicket,"小红").start(); } }死锁:都在相互等待对方的资源。
产生死锁的4个必要条件:
互斥条件:一个支援每次只能被一个进程使用。请求和保持条件:一个进程因请求资源而堵塞时,对方获得的资源褒词不放。不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。避免程序中出现死锁。
Lock是接口,常用实现类ReentrantLock(可重复锁)。
import java.util.concurrent.locks.ReentrantLock; //测试lock锁 public class TestLock { public static void main(String[] args) { TestLock1 testLock11 = new TestLock1(); new Thread(testLock11).start(); new Thread(testLock11).start(); new Thread(testLock11).start(); } } class TestLock1 implements Runnable{ int ticket = 10; ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true){ try { lock.lock(); if(ticket >0){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticket--); }else { break; } }finally { lock.unlock(); } } } }生产者消费者 问题