建一个网站需要哪些人,aso是什么意思,可拖拽 网站建设,百度seo和谷歌seo有什么区别1 相关概念
并发#xff1a;两个或多个事件在同一时间段内发生【多个任务交替执行】 并行#xff1a;两个或多个事件在同一时刻发生【多个任务同时执行】 进程#xff1a;进入内存的程序 内存#xff1a;所有应用程序都要进入到内存中执行 临时存储RAM 线程#xff1a;进…1 相关概念
并发两个或多个事件在同一时间段内发生【多个任务交替执行】 并行两个或多个事件在同一时刻发生【多个任务同时执行】 进程进入内存的程序 内存所有应用程序都要进入到内存中执行 临时存储RAM 线程进程的一个执行单元负责程序的执行 一个程序至少有一个进程一个进程可以包含多个线程 CPU中央处理器对数据进行计算指挥软件和硬件 单线程CPU在多个线程之间做高速的切换轮流执行多个线程效率低 多线程多个线程在多个任务之间做高速的切换速度是单线程的多倍多个线程之间互不影响
线程调度
分时调度所有线程轮流使用CPU平均分配每个线程占用CPU的时间抢占式调度优先让优先级高的线程使用CPU如果优先级相同则随机选择一个Java中使用抢占式调度。
2 主线程
主线程执行main方法的线程 主线程的过程JVM执行main方法main方法进入到栈内存JVM会找操作系统开辟一条main方法的执行路径CPU根据路径来执行main方法这个路径就是主线程。 单线程执行从main方法开始自上而下依次执行
public class Person {private String name;public Person(String name) {this.name name;}public void run(){for (int i 0; i 3; i) {System.out.println(name i);}}
}public class MainThread {public static void main(String[] args) {Person p1 new Person(张三);p1.run();Person p2 new Person(李四);p2.run();}
}3 创建多线程程序-法1
3.1 创建Thread类的子类
创建Thread类的子类在子类中重写run方法设置线程任务创建子类对象调用start方法开始新的线程执行run方法
main压栈执行后在堆内存中创建线程子类对象栈中保存对象地址。如果调用run方法run方法压栈执行则是单线程处理。如果调用start方法会开辟新的栈空间执行run方法。CPU可以选择不同的栈空间。
start使线程开始执行JVM调用线程的run方法两个线程并发运行 main线程-----创建新线程执行run
public class MyThread extends Thread {Overridepublic void run() {for (int i 0; i 5; i) {System.out.println(run i);}}
}public class MyThreadTest {public static void main(String[] args) {MyThread mt new MyThread();mt.start();for (int i 0; i 5; i) {System.out.println(main i);}}
}同优先级下随机抢占谁抢到谁执行
3.2 Thread类常用方法
获取线程名称getName()、Tread.currentTread()
Tread t new Tread();
sout(t.getName());//名称Tread t Tread.currentTread();
sout(t);//名称设置线程名称setName()、构造方法参数传递线程名称
public class MyThreadTest {public static void main(String[] args) {MyThread mt1 new MyThread(张三);mt1.start();MyThread mt2 new MyThread();mt2.setName(李四);mt2.start();}
}public class MyThread extends Thread {public MyThread(String name) {super(name);public MyThread() {}Overridepublic void run() {System.out.println(getName());}
}线程休眠sleep(long millis) 毫秒结束后程序继续执行
模拟秒表 示例
public class MyThreadTest {public static void main(String[] args) throws InterruptedException {for (int i 1; i 60; i) {System.out.println(i);Thread.sleep(1000);}}
}4 创建多线程程序-法2【推荐使用】
4.1 创建Runnable实现类
创建Runanable接口的实现类实现类中重写run方法设置线程任务创建实现类的对象创建Thread类对象构造方法中传递Runnale的实现类对象调用Thread类中的start方法
public class RunnableImpl implements Runnable {Overridepublic void run() {for (int i 0; i 5; i) {System.out.println(Thread.currentThread() i);}}
}public class MyThreadTest {public static void main(String[] args) throws InterruptedException {RunnableImpl run new RunnableImpl();Thread t new Thread(run);t.start();for (int i 0; i 5; i) {System.out.println(Thread.currentThread() i);}}
}4.2 两种实现方法的区别
Runnable的优点
避免了单继承的局限性类继承了Thread类就不能继承其他类了实现Runnable接口还可以实现其他接口。增强了程序的扩展性降低了程序的耦合性解耦。把设置线程任务和开启线程进行了分离。实现类中重写run方法来设置线程任务创建Thread类对象调用start来开启新线程。想要什么任务就传递什么实现类对象。
5 匿名内部类创建线程
匿名内部类简化代码。 把1.子类继承父类 2.重写父类 3.创建子类对象 — 一步完成 把1.实现实现类接口 2.重写接口方法 3.创建实现类对象 — 一步完成
public class MyThreadTest {public static void main(String[] args) throws InterruptedException {//Thread法new Thread(){Overridepublic void run() {for (int i 0; i 5; i) {System.out.println(Thread.currentThread() i);}}}.start();//Runnable法new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i 5; i) {System.out.println(Thread.currentThread() i);}}}).start();}
}6 线程安全
共享资源产生安全问题
public class RunnableImpl implements Runnable {//共享票源private int tickets 100;Overridepublic void run() {//重复卖票while(true){if(tickets 0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(卖第tickets张票);tickets--;}}}
}public class MyThreadTest {public static void main(String[] args) throws InterruptedException {RunnableImpl r new RunnableImpl();Thread t1 new Thread(r);Thread t2 new Thread(r);Thread t3 new Thread(r);t1.start();t2.start();t3.start();}
}出现了重复的票 窗口Thread-2在卖第100张票 窗口Thread-0在卖第100张票 窗口Thread-1在卖第100张票 窗口Thread-1在卖第97张票 窗口Thread-2在卖第97张票 窗口Thread-0在卖第97张票 窗口Thread-0在卖第94张票 窗口Thread-2在卖第94张票 出现了不存在的票 窗口Thread-2在卖第0张票 窗口Thread-1在卖第-1张票 线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作而无写操作一般来说这个全局变量是线程安全的若有多个线程同时执行写操作一般都需要考虑线程同步否则的话就可能影响线程安全。
注意访问共享数据的时候无论是否时区CPU执行权其他线程只能等待等当前线程完全结束后其他线程再继续。
7 同步技术的原理
使用了一个锁对象这个对象叫同步锁也叫对象监视器。多个线程一起抢夺CPU执行权谁抢到了谁执行run方法遇到同步代码块。
此时抢到CPU的当前线程T0会检查同步代码块是否有锁对象如果有则获取锁对象进入到同步中进行。
另一进程T1抢到CPU后发现没有锁对象了则进入阻塞状态等待锁对象的归还直到上一进程T0执行完同步代码块才归还锁对象T1进程才可以获取到锁对象进入到同步中执行。
同步中的线程没有执行完毕不会释放锁同步外的线程没有锁对象无法进入同步代码块。同步保证了只有一个线程再同步中执行共享数据保证安全但牺牲了效率。
7.1 同步方法
定义同步方法解决线程安全问题
把访问了共享数据的代码取出来放到一个方法中在方法上添加synchronized
同步方法也会锁住方法内部只让一个线程执行锁对象是实现类对象new RunnableImpl()也就是this。
public class RunnableImpl implements Runnable {//共享票源private int tickets 100;Overridepublic void run() {while(true){sell();}}public synchronized void sell(){if(tickets 0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}String name Thread.currentThread().getName();System.out.println(窗口name在卖第tickets张票);tickets--;}}
}7.2 静态同步方法
加static关键字锁对象不是thisthis是创建对象之后产生的static优先于对象的创建静态同步方法的锁对象是本类的class属性—class文件对象反射
RunnableImpl.class7.3 Lock锁
JDK1.5之后出现Lock接口实现了synchronized方法和语句可获得更广泛的锁操作。
在成员位置创建一个ReentrantLock对象在可能会出现安全问题的代码前调用Lock接口的lock方法获取锁在可能会出现安全问题的代码后调用Lock接口的unlock方法释放锁
public class RunnableImpl implements Runnable {//共享票源private static int tickets 100;Lock lock new ReentrantLock();Overridepublic void run() {while(true){lock.lock();if(tickets 0){try {Thread.sleep(10);String name Thread.currentThread().getName();System.out.println(窗口name在卖第tickets张票);tickets--;} catch (InterruptedException e) {e.printStackTrace();}finally {lock.unlock();}}}}
}8 线程状态
新建状态new运行状态runnable阻塞状态blocked死亡状态terminated休眠状态time_waiting【等待时间】永久等待waiting【等待唤醒】
new — start() CPU — runnable new — start() - CPU — blocked
runnable — stop() / run(over) — terminated runnable — sleep / wait — timed_waiting timed_waiting — time over - CPU— blocked timed_waiting — time over CPU— runnable runnable — Object.wait() — waiting waiting — Object.notify() CPU — runnable waiting — Object.notify() - CPU — blocked
9 线程通信
9.1 等待唤醒案例
创建消费者线程申请资源种类和数量调用wait方法放弃CPU进入waiting状态。创建生产者线程产生资源之后调用notify唤醒消费者。两个线程必须被同步代码块包裹确保只有一个在执行。同步的锁对象必须唯一只有锁对象可以调用wait和notify方法。
public class WaitAndNotify {public static void main(String[] args) {//锁对象Object obj new Object();//消费者new Thread(){Overridepublic void run() {while(true){synchronized (obj){System.out.println(申请资源);try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(拿到资源);System.out.println(------------);}}}.start();//生产者new Thread(){Overridepublic void run() {while (true){try {System.out.println(准备资源);Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj){obj.notify();System.out.println(资源已备好);}}}}.start();}
}Object.wait(long m)无参数的wait需要等待notify唤醒有参数的wait等到时间结束后进入到runnable有CPU或者blocked无CPU状态相当于sleep(long m)但如果时间结束前notify被调用则提前醒来。
Object.notifyAll()唤醒监视器上所有的线程。
9.2 生产者和消费者案例
包子
public class BaoZi {String pi;//包子皮String xian;//包子馅boolean flag false;//是否有包子
}包子铺
public class BaoZiPu extends Thread {private BaoZi bz;//锁对象public BaoZiPu(BaoZi bz){this.bz bz;}Overridepublic void run() {int count 0;//持续生产包子while(true){synchronized (bz){if(bz.flag true){try {bz.wait();} catch (InterruptedException e) {e.printStackTrace();}}//被唤醒后执行 包子铺生产包子if(count % 2 0){bz.pi 薄皮;bz.xian 三鲜;}else {bz.pi 厚皮;bz.xian 牛肉;}count;System.out.println(包子铺正在生产bz.pibz.xian包);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}bz.flag true;bz.notify();System.out.println(bz.pibz.xian包已生产好吃货可以开始吃包子了);}}}
}吃货
public class ChiHuo extends Thread {private BaoZi bz;public ChiHuo(BaoZi bz){this.bz bz;}Overridepublic void run() {while(true){synchronized (bz){if(bz.flag false){try {bz.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(吃货正在吃bz.pibz.xian包);//吃完包子bz.flag false;//唤醒包子铺bz.notify();System.out.println(吃货已经吃完了bz.pibz.xian包包子铺开始生产包子);System.out.println();}}}
}测试类
public class Test {public static void main(String[] args) {BaoZi bz new BaoZi();BaoZiPu bzp new BaoZiPu(bz);ChiHuo ch new ChiHuo(bz);bzp.start();//生产包子ch.start();//吃包子}
}10 线程池
10.1 概念
线程池其实就是一个容纳多个线程的容器其中的线程可以反复使用省去了频繁创建线程对象的操作无需反复创建线程而消耗过多资源。
线程池的优点
降低资源消耗。减少了创建和销毁线程的次数每个工作线程都可以被重复利用可执行多个任务。提高响应速度。当任务到达时任务可以不需要的等到线程创建就能立即执行。提高线程的可管理性。可以根据系统的承受能力调整线程池中工作线线程的数目防止因为消耗过多的内存而把服务器累趴下(每个线程需要大约1MB内存线程开的越多消耗的内存也就越大最后死机)。
10.2 线程池的使用
JDK1.5出现线程池的工厂类Executor用来生产线程池
Executors类的静态方法
newFixedThreadPool(int nThread)创建可重用固定线程数的线程池返回值是ExecutorService接口的实现类对象使用ExecutorService接口接收【面向接口编程】
ExecutorService接口
shutdown关闭销毁线程池submit(Runnable task)提交一个Runnable任务用于执行
使用步骤
使用工厂类Executors里面的静态方法newFixedThreadPool生产一个线程池创建一个实现类实现Runnable重写run设置线程任务调用ExecutorService中的方法submit传递线程任务实现类开启线程执行run方法。调用ExecutorService中的方法shutdown销毁线程池【不建议销毁线程池】
public class RunnableImpl implements Runnable {Overridepublic void run() {System.out.println(Thread.currentThread().getName()创建了一个新的线程执行);}
}public class ThreadPool {public static void main(String[] args) {ExecutorService es Executors.newFixedThreadPool(2);es.submit(new RunnableImpl());es.submit(new RunnableImpl());es.submit(new RunnableImpl());es.submit(new RunnableImpl());}
}pool-1-thread-2创建了一个新的线程执行 pool-1-thread-1创建了一个新的线程执行 pool-1-thread-2创建了一个新的线程执行 pool-1-thread-1创建了一个新的线程执行