win2008 iis7发布网站阿里云网站备份

web/2025/10/8 15:24:18/文章来源:
win2008 iis7发布网站,阿里云网站备份,哪些网站可以免费做代码,广西网站建设建议多线程 程序、进程、线程的概念 程序#xff1a;是指令和数据的有序集合#xff0c;是一个静态的概念。比如#xff0c;在电脑中#xff0c;打开某个软件#xff0c;就是启动程序。 进程#xff1a;是执行程序的一次执行过程#xff0c;是一个动态的概念#xff0c;…多线程 程序、进程、线程的概念 程序是指令和数据的有序集合是一个静态的概念。比如在电脑中打开某个软件就是启动程序。 进程是执行程序的一次执行过程是一个动态的概念是系统资源的分配单位。 当我们运行一个程序后这个程序的进程就会启动。将来可以在任务管理器中查看进程。 线程一个进程中可以包含若干个线程至少包含一个线程。线程是CPU调度和执行的单位。 在同一个进程中可以执行多个任务每个任务就可以看成是一个线程。 比如放音乐的时候可以一边放音乐一边下载其他音乐 看电影的时候播放器中的画面、声音、弹幕都是独立的线程。 总结 进程可以指运行中的程序特点动态性、独立性、并发性。 线程是进程内部的执行单位它是程序中一个顺序控制流程。 多线程就是一个进程中同时有多个线程用于完成不同的工作。 Java中的线程 主线程、子线程 main()方法就是主线程的入口其中执行的内容就是主线程内容其他的子线程需要通过特殊的类去创建在main()方法中执行main()方法必须最后执行完毕因为它要执行各种关闭操作。 package com.day17.thread1;public class ThreadDemo {public static void main(String[] args) {//测试main()方法中的线程//返回当前main()方法中的线程对象Thread thread Thread.currentThread();//返回当前线程名称System.out.println(thread.getName());//设置main线程的名字thread.setName(主线程);System.out.println(thread.getName());} }Java中线程的创建和启动 1、继承Thread类 构造方法 Thread() 分配一个新的 Thread对象。 Thread(Runnable target) 分配一个新的 Thread对象。 Thread(Runnable target, String name) 分配一个新的 Thread对象。 Thread(String name) 分配一个新的 Thread对象。 常用普通方法 static Thread currentThread() 返回对当前正在执行的线程对象的引用。 String getName() 返回此线程的名称。 void join() 等待这个线程死亡。 void run() 如果这个线程使用单独的Runnable运行对象构造则调用该Runnable对象的run()方法; 否则此方法不执行任何操作并返回。 void setName(String name) 将此线程的名称更改为等于参数 name 。 void setPriority(int newPriority) 更改此线程的优先级。 static void sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停暂时停止执行具体取决于系统定时器和调度程序的精度和准确性。 void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法。 static void yield() 对调度程序的一个暗示即当前线程愿意产生当前使用的处理器。 继承Thread类创建多线程的步骤 1、继承Thread类 2、重写run方法将来要其他线程要执行的逻辑内容都放在run方法中 3、实例化子类对象后调用start方法来启动线程 调用start方法的时候是在告诉JVM分配线程去调用run()方法 调用run()方法和start()方法的区别 run方法是继承了Thread类重写的一个方法 当我们调用start()方法的时候JVM会启动一个线程并执行run()方法中的内容 直接调用run()方法会把run()当作main()线程下的一个普通方法执行 不会在某个线程中执行所以并不是多线程工作。 package com.day17.thread1;public class ThreadDemo01 extends Thread{//继承Thread类创建多线程的步骤//1、继承Thread类//2、重写run方法将来要其他线程要执行的逻辑内容都放在run方法中//3、实例化子类对象后调用start方法来启动线程//调用start方法的时候是在告诉JVM分配线程去调用run()方法Overridepublic void run() {for (int i 0; i 10; i) {//获取当前线程名称System.out.println(Thread.currentThread().getName() i);}}public static void main(String[] args) {//main方法既是程序的入口也是一个主线程也是子线程启动的入口ThreadDemo01 thread01 new ThreadDemo01();thread01.setName(子线程1);thread01.start();//启动线程//直接调用run方法JVM默认会将run方法作为普通方法交给main线程来执行// thread01.run();// ThreadDemo01 thread02 new ThreadDemo01(); // thread02.setName(子线程2); // thread02.start();} }2、实现Runnable接口 1、实现Runnable接口重写run()方法 2、创建对象把对象作为参数传递到Thread类中中创建Thread对象创建出来的Thread对象才是真正的线程对象 3、通过线程对象调用start()方法 package com.day17.thread2;//1、实现Runnable接口重写run()方法 //2、创建对象把对象作为参数传递到Thread类中中创建 //Thread对象创建出来的Thread对象才是真正的线程对象 //3、通过线程对象调用start()方法 public class ThreadDemo 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) {//先创建Runnable接口实现类对象ThreadDemo thread01 new ThreadDemo();// //再通过实现类对象创建Thread对象// Thread t1 new Thread(thread01);// //通过Thread对象调用start()方法// t1.start();// //将创建Runnable接口对象作为参数直接传入Thread类的构造方法// Thread t2 new Thread(new ThreadDemo(), 子线程2);// t2.start();Thread t1 new Thread(thread01, 小红);Thread t2 new Thread(thread01, 小明);t1.start();t2.start();} } 使用匿名内部类实现Runnable接口实现多线程效果 package com.day17.thread2; //使用匿名内部类实现Runnable接口实现多线程效果 public class ThreadDemo02 {public static void main(String[] args) {new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName(): i);}}},小明).start();new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName(): i);}}},小红).start();} }lambda表达式的写法实现Runnable接口完成多线程实现 是一种函数式编程 语法()-{} ()中将来传递参数{}写重写接口的方法 package com.day17.thread2; //lambda表达式的写法实现Runnable接口完成多线程实现 //是一种函数式编程 //语法()-{} ()中将来传递参数{}写重写接口的方法 public class ThreadDemo03 {public static void main(String[] args) {new Thread(()-{for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName(): i);}},小红).start();new Thread(()-{for (int i 0; i 10; i) {System.out.println(Thread.currentThread().getName() : i);}},小明).start();} }3、实现Callable接口 实现步骤 1.实现Callable接口 2.以实现类为参数创建FutureTask对象 3.将FutureTask对象作为参数创建Thread对象 4.调用start方法 package com.day17.thread7;import java.util.concurrent.Callable;public class CallableDemo implements Callable {Overridepublic Integer call() throws Exception {System.out.println(Thread.currentThread().getName()-call方法被执行了);return 10;} }package com.day17.thread7;import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;public class TestCallable {public static void main(String[] args) throws ExecutionException, InterruptedException {//创建FutureTask对象FutureTaskInteger futureTask new FutureTaskInteger(new CallableDemo());new Thread(futureTask).start();//获取返回call方法的返回值要通过FutureTask对象获取System.out.println(futureTask.get());} }4、使用Executors工具类创建线程池 package com.day17.thread8;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class ExecutorsDemo extends Thread{Overridepublic void run() {System.out.println(Thread.currentThread().getName()正在执行...);}public static void main(String[] args) {//通过Executors工具类创建线程池//可变大小的线程池ExecutorService pool Executors.newCachedThreadPool();//固定大小的线程池 // ExecutorService pool Executors.newFixedThreadPool(2);//单个的 // ExecutorService pool Executors.newSingleThreadExecutor();//创建线程对象ExecutorsDemo t1 new ExecutorsDemo();ExecutorsDemo t2 new ExecutorsDemo();ExecutorsDemo t3 new ExecutorsDemo();ExecutorsDemo t4 new ExecutorsDemo();//把线程对象放入池子中pool.execute(t1);pool.execute(t2);pool.execute(t3);pool.execute(t4);//关闭线程池pool.shutdown();} }package com.day17.thread8;import java.util.Date;public class ExecutorsDemo02 implements Runnable{Overridepublic void run() {System.out.println(Thread.currentThread().getName()开始执行new Date());try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()结束执行new Date());} } package com.day17.thread8;import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit;public class ThreadPoolExecutorDemo {public final static int CORE_POOL_SIZE 5;public static final int MAX_POOL_SIZE 10;public static final Long KEEP_ALIVE_TIME 1L;//使用阿里巴巴推荐的ThreadPoolExecutor创建线程池public static void main(String[] args) {ThreadPoolExecutor poolExecutor new ThreadPoolExecutor(CORE_POOL_SIZE,MAX_POOL_SIZE,KEEP_ALIVE_TIME,TimeUnit.SECONDS,new ArrayBlockingQueue(100));for (int i 0; i 10; i) {ExecutorsDemo02 demo02 new ExecutorsDemo02();poolExecutor.execute(demo02);}//关闭线程池poolExecutor.shutdown();} } 继承Thread类和实现Runnable接口的使用区别 继承Thread类使用起来比较方便可以直接使用Thread类中的一些方法但是不能实现资源共享。 实现Runnable接口会让编写更具有统一性解决了继承的局限性可以实现线程之间的资源共享。 Runnable和Callable的区别 相同点都是接口都可以编写多线程程序都需要通过Thread.start()方法启动 不同点 1.Runnable接口的run方法没有返回值 Callable接口的call方法有返回值是一个泛型可以结合FutureTask对象获取对象的返回值。 2.Runnable接口的run方法只能抛出运行时异常只能用try/catch 线程执行的生命周期 新生状态new一个线程对象该线程对象就处于新生状态这个时候该线程对象具有自己的内存空间。 就绪状态新生状态的线程对象调用了start方法之后进入就绪状态这时候线程具有运行条件再等待CPU分配时间片。 如果系统选定了一个就绪状态的线程就会从就绪状态进入执行状态这个动作称为CPU调度。 运行状态获取到执行的时间片这时候会执行线程对象中的run方法直到任务完成后死亡或者等待资源阻塞。 阻塞状态运行状态下的线程执行力sleep方法或者io资源阻塞、wait方法、synchronized同步作用下会进入阻塞状态。 阻塞状态下线程不能进入就绪队列只有阻塞原因清除才会重新进入就绪状态中排队等待被系统选中后从原来停止的位置继续执行。 死亡状态线程正常执行完了它的工作、线程被强制终止了、线程抛出未被捕获的异常线程都会进入死亡状态。 package com.day17.thread3;public class ThreadDemo05 implements Runnable{Overridepublic void run() {System.out.println(我正在运行);try {Thread.sleep(2000);//休眠2秒System.out.println(线程休眠后继续运行);} catch (InterruptedException e) {e.printStackTrace();System.out.println(线程被中断);}}public static void main(String[] args) {Thread t new Thread(new ThreadDemo05());System.out.println(线程t进入新生状态1);t.start();System.out.println(线程进入就绪状态2);} }线程的调度 void join() 等待这个线程死亡。 void setPriority(int newPriority) 更改此线程的优先级。 static void yield() 对调度程序的一个暗示即当前线程愿意产生当前使用的处理器。 package com.day17.thread3;public class ThreadDemo06 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) {//void setPriority(int newPriority)//更改此线程的优先级并不会一定将线程优先执行完毕Thread t1 new Thread(new ThreadDemo06(), A);Thread t2 new Thread(new ThreadDemo06(), B);// t1.setPriority(Thread.MAX_PRIORITY); // t2.setPriority(Thread.MIN_PRIORITY); // // t1.start(); // t2.start();//void join()//等待这个线程死亡。t1.start();for (int i 1; i 10; i) {if (i5){try { // t1.join();//插队System.out.println(线程礼让);//线程礼让方法执行之后不代表后面马上会执行其他内容//只是礼让下次执行机会继续再公平竞争Thread.yield();} catch (Exception e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() i);}//static void yield()//对调度程序的一个暗示即当前线程愿意产生当前使用的处理器。} }void setDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。 当运行的唯一线程都是守护进程线程时Java虚拟机将退出。 守护线程运行在后台的一种特殊线程独立于控制终端并且周期性执行某种任务 setDaemon()这个方法必须在启动线程前调用 比如JVM中垃圾回收、内存管理等线程都是守护线程 //1.设为守护线程后主线程结束守护线程也会结束 //2.普通线程主线程结束后普通线程还会继续运行 package com.day17.thread3;public class ThreadDemo07 extends Thread{Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(守护线程);}}public static void main(String[] args) {System.out.println(程序开始);ThreadDemo07 t new ThreadDemo07();//1.设为守护线程后主线程结束守护线程也会结束//2.普通线程主线程结束后普通线程还会继续运行t.setDaemon(true);t.start();//主线程休眠5秒try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(主线程运行结束);} }线程安全问题 在多线程的运行下程序运行的结果和我们预期的结果不一致排除代码错误的情况 这种情况就可以看作是线程安全问题每次运行的结果可能都会不同问题不易复现 解决比较困难。 package com.day17.thread4;public class T1A {//出现线程安全这个类中必须得有共享资源int num;public int getNum() {return num;}public int updateNum(){return num;} } package com.day17.thread4;public class T1 extends Thread{T1A t1a new T1A();Overridepublic void run() {while (true){System.out.println(现在运行的是: Thread.currentThread().getName() num t1a.updateNum());try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {T1 t1 new T1();new Thread(t1).start();new Thread(t1).start();new Thread(t1).start();new Thread(t1).start();} } 通过反编译查看线程安全文件的原因 其实出现线程安全问题的原因就是代码执行的过程并不是原子性的操作一个线程在执行的时候会有其它线程读取到中间步骤或者读取到未修改的值所以导致线程安全问题的出现。 通过synchronized关键字解决线程安全问题。 package com.day17.thread4;import java.util.ArrayList;/* 线程同步示例*/ public class ThreadDemo08 {public static void main(String[] args) {//线程不安全的ListArrayListString list new ArrayList();for (int i 0; i 20000; i) {new Thread(()-{synchronized (list){list.add(Thread.currentThread().getName());}}).start();}for (int i 5; i 0; i--) {try {Thread.sleep(1000);System.out.println(倒计时i);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(list.size());} } 什么样的情况会发生线程安全问题 1.多线程环境 2.存在共享资源多个线程会去访问共享资源 3.存在并发修改共享资源的情况 线程同步 1、为什么要使用多线程完成并发编程 多线程可以充分利用CPU计算能力通过并发编程的形式可以将多核CPU的计算能力发挥到极致提升性能。 方便进行业务拆分提升系统的并发能力和性能。 2、并发编程的缺点 并发编程虽然能提高效率但是也会产生各种问题比如线程安全、死锁、上下文切换、内存泄露... 3、并发编程三要素【面试】 1.原子性保证程序执行的步骤不可再分要么全部成功要么全部失败。 2.可见性一个线程对共享资源的修改另一个线程可以马上看到。 synchronized、volatile 3. 有序性程序执行的顺序按照代码的先后顺序执行JVM中可能会对指令进行重排序  线程切换可能会带来原子性问题。 缓存导致可见性问题。 编译优化带来有序性问题。 以上三个问题的出现就是线程安全问题的原因。 Java中解决线程安全问题 原子性synchronized、Lock、JDK、Atomic开头的原子类 可以解决原子性问题 可见性synchronized、volatile、Lock 可以解决可见性问题 有序性HappensBefore规则 解决有序性问题 并发相关的概念 并发多个任务在同一个CPU核上按照时间片轮流执行从逻辑上看多个任务是同时执行的。 并行单位时间内多个处理器同时处理多个任务是真正的同时执行。 串行有多个任务由同一个线程按照顺序执行由于任务、方法都在一个线程下执行不存在线程不安全的情况。 高并发同一个对象被多个对象同时操作存在线程安全问题可以通过线程同步来解决并发问题。 线程同步其实就是一种等待机制多个需要同时访问某个对象的线程进入对象的等待池中形成队列前面的线程用完了下个线程再使用。 Java中怎么实现线程同步 Java为了保证数据访问的安全性在多线程中可以加入锁机制synchronized 如果一个线程获取到锁把资源独占其他线程等待前面线程用完之后释放锁。 synchronized关键字的用法 synchronized可以用来控制线程同步在多线程情况下加了这个关键字的代码不会被多个线程执行。 synchronized可以用来修饰类、方法、变量。 早期版本的synchronized比较笨重jdk1.6之后引入了大量的优化。 常用的写法 1、直接写在方法上称为同步方法 public synchronized void method(){} 每个synchronized方法必须获取到调用该方法的对象的锁才能执行否则该线程处于阻塞状态 如果线程拿到锁了就能独占该锁直到方法运行结束释放锁其他的被阻塞的线程才能获取锁。 package com.day17.thread4;/* 初识并发问题模拟抢票案例*/ public class TicketDemo implements Runnable{//设置票数票数是公共的资源多个线程共享private int ticketNumber 10;boolean flagtrue;Overridepublic void run() {while (flag){buyTicket();try {//模拟网络延迟Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}//写一个买票方法public synchronized void buyTicket(){if (ticketNumber 0){flagfalse;return;}// try {// //模拟网络延迟// Thread.sleep(100);// } catch (InterruptedException e) {// e.printStackTrace();// }System.out.println(Thread.currentThread().getName()-抢到了第 ticketNumber-- 张票);}public static void main(String[] args) {TicketDemo t new TicketDemo();//把实现类对象传入到Thread对象中创建Thread对象new Thread(t,小明).start();new Thread(t,小红).start();new Thread(t,黄牛).start();} } 2、修饰静态方法 当synchronized静态方法上的时候就是相当于给类加锁锁的是每个类的Class类对象 会作用于所有对象的实例。 3、使用synchronized修饰代码块成为同步代码块 synchronized(obj){} 同步代码块一般需要传入一个参数这个参数(obj)可以是任意对象将来一般将具有共享资源的对象放在这里作为同步监视器。 package com.day17.thread4;public class TicketDemo02 implements Runnable{//设置票数票数是公共的资源多个线程共享private int ticketNumber 10;boolean flagtrue;Object object new Object();Overridepublic void run() {while (flag){buyTicket();try {//模拟网络延迟Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}//写一个买票方法public void buyTicket(){synchronized (object){if (ticketNumber 0){flagfalse;return;}System.out.println(Thread.currentThread().getName()-抢到了第 ticketNumber-- 张票);}}public static void main(String[] args) {TicketDemo02 t new TicketDemo02();//把实现类对象传入到Thread对象中创建Thread对象new Thread(t,小明).start();new Thread(t,小红).start();new Thread(t,黄牛).start();} } synchronized优缺点 优点解决了线程安全问题 缺点性能下降影响效率修饰方法的话每次调用方法就会产生锁浪费资源可能产生死锁 Lock锁 JDK1.5开始提供的一个更强大的线程同步锁 通过显式的定义同步锁对象来实现同步也就是Lock对象。 锁是用于通过多个线程控制对共享资源的访问的工具。 通常锁提供对共享资源的独占访问 一次只能有一个线程可以获取锁并且对共享资源的所有访问都要求首先获取锁。 使用方式 使用Lock接口的常用实现类ReentrantLock ReentrantLock是一个可重入互斥Lock具有与使用synchronized方法 和语句访问的隐式监视锁相同的基本行为和语义但具有扩展功能 语法 class X { private final ReentrantLock lock new ReentrantLock(); // ... public void m() { lock.lock();//手动调用lock方法加锁 try { // ... method body } finally { lock.unlock() ; //释放锁 } } } package com.day17.thread4; /* Lock*/ import java.util.concurrent.locks.ReentrantLock;public class TicketDemo03 implements Runnable{//设置票数票数是公共的资源多个线程共享private int ticketNumber 20;boolean flagtrue;ReentrantLock lock new ReentrantLock();Overridepublic void run() {while (flag){buyTicket();}}//写一个买票方法public void buyTicket(){try {lock.lock();if (ticketNumber 0){flagfalse;return;}System.out.println(Thread.currentThread().getName()-抢到了第 ticketNumber-- 张票);//模拟网络延迟Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}finally {lock.unlock();}}public static void main(String[] args) {TicketDemo03 t new TicketDemo03();//把实现类对象传入到Thread对象中创建Thread对象new Thread(t,小明).start();new Thread(t,小红).start();new Thread(t,黄牛).start();}} Lock和synchronized的区别 1.synchronized 是一个关键字Lock是一个接口ReentrantLock是一个类类中提供了比synchronized更多灵活性的操作比如可以被继承、可以有方法、可以有各种类变量 2.synchronized早期效率比较低jdk1.6之后做了优化后性能较好 3.ReentrantLock使用起来比较灵活但是必须要有开启锁和释放锁的动作synchronized不需要手动开启、释放锁 4.ReentrantLock一般只适用于代码块锁而synchronized可以用于修饰类、变量、方法 Lock和synchronized选择用哪个 因为JDK1.6之后synchronized做了很多优化所以synchronized效率不比Lock而且使用更加简单一般情况下就使用synchronized 死锁 概念 指的是两个或者两个以上的线程中在执行过程中由于竞争资源或者由于彼此通信造成的一种阻塞现象如果没有外力作用他们无法推进下去此时这种状态称为系统的死锁这些永远在互相等待的线程称为死锁线程。 出现死锁后程序不会有异常也不会出现提示只是线程处于阻塞状态无法继续将来编写程序要避免死锁的发生。 出现死锁的条件 1.互斥条件线程对于分配到的资源具有排他性也就是一个资源只能被一个线程占用直到被该线程释放。 2.请求与保持条件一个线程因为请求被占用资源而发生阻塞时对已经获取的资源保持不放。 3.不剥夺条件线程在获取资源后未使用完之前不能被其他线程强行剥夺。 4.循环等待条件当发生死锁的时候所有等待的线程必定会形成一个环路类似于死循环造成永久阻塞。 怎么避免死锁 破坏上面四个条件中的任意一个就不会产生死锁。 package com.day17.deadLock5;//茶杯对象 public class TeaCup { }package com.day17.deadLock5;//牙膏对象 public class ToothPaste { }package com.day17.deadLock5;public class BrushTooth implements Runnable{String name;//谁拿了对象int choice;//0茶杯1牙膏static TeaCup teaCup new TeaCup();static ToothPaste toothPaste new ToothPaste();public BrushTooth(String name, int choice) {this.name name;this.choice choice;}Overridepublic void run() {try {brushTooth();} catch (InterruptedException e) {e.printStackTrace();}}//写一个刷牙方法public void brushTooth() throws InterruptedException {//先拿茶杯再拿牙膏if (choice 0){synchronized (teaCup){System.out.println(name拿到了茶杯等待拿牙膏刷牙);Thread.sleep(1000);synchronized (toothPaste){System.out.println(name拿到牙膏开始刷牙);}}}else {//先拿牙膏再拿茶杯synchronized (toothPaste){System.out.println(name拿到了牙膏等待拿茶杯刷牙);Thread.sleep(1000);synchronized (teaCup){System.out.println(name拿到茶杯开始刷牙);}}}} }package com.day17.deadLock5;public class Test {public static void main(String[] args) {BrushTooth t1 new BrushTooth(A, 0);BrushTooth t2 new BrushTooth(B, 1);new Thread(t1).start();new Thread(t2).start();} }volatile关键字 Java提供了volatile关键字用来解决多线程中的部分问题。 volatile可以用来保证可见性和有序性不能保证原子性还会出现线程安全问题。 package com.day17.thread6;public class ThreadDemo09 {public int num0;public boolean flag false;//不加volatile程序一直在运行//volatile保证了类属性在多个线程中的可见性//public volatile boolean flag false;//synchronized也可以保证可见性//通过给方法修饰后间接控制属性可见性public synchronized boolean isFlag() {return flag;}public synchronized void setFlag(boolean flag) {this.flag flag;}public synchronized void addNum(){num;}public int getNum() {return num;}public static void main(String[] args) {ThreadDemo09 t1 new ThreadDemo09();new Thread(()-{for (int i 0; i 5; i) {t1.addNum();System.out.println(addNum方法被调用 i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}//将flag设为true// t1.flagtrue;t1.setFlag(true);System.out.println(已经将flag设为true了。);}).start();new Thread(()-{System.out.println(线程2正在执行);// while (!t1.flag){// }while (!t1.isFlag()){}System.out.println(num的值是t1.getNum());}).start();} } package com.day17.thread6;public class ThreadDemo10 {//volatile不能保证原子性public volatile int num0; // public int num0;// public synchronized void addNum(){public void addNum(){num;}public int getNum() {return num;}public static void main(String[] args) {ThreadDemo10 t1 new ThreadDemo10();//循环10次每次创建一个子线程每个子线程做了100次 num//如果有原子性的线程安全的最终的值应该是1000//在属性前加上volatile不能保证原子性所以最终的值不是1000//使用synchronized关键字加在方法前面可以保证原子性for (int i 0; i 10; i) {new Thread(()-{for (int j 0; j 100; j) {t1.addNum();try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}//获取值for (int i 0; i 10; i) {System.out.println(num的值是t1.getNum());try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}} }synchronized和volatile的区别 synchronized表示只有一个线程可以获取作用对象的值执行代码会阻塞其他线程。 volatile表示变量在CPU的寄存器中是不确定的必须从内存中读取保证多线程下变量的可见性 禁止指令重排有序性。 区别 1.volatile是用来修饰变量的synchronized可以修饰类、方法、变量。 2.volatile只能实现变量的可见性不能保证原子性synchronized可以保证原子性和可见性。 3. volatile不会造成线程阻塞synchronized会造成线程阻塞。 4.volatile标记的变量不会被编译器优化synchronized标记的变量可以被编译器优化。 5.volatile性能比synchronized要好。 线程交互 Object类中的方法 wait()、notify()、notifyAll() wait()方法释放占有的对象锁线程进入等待池释放CPU 其他正在等待的线程可以拿到锁获取到锁的线程可以执行程序。 notify()方法该方法会唤醒因为调用wait()方法而等待的线程其实就是对 对象锁 的唤醒 被唤醒的线程可以有机会继续获得对象锁从而执行程序。 另一个线程调用notify()后不会马上释放锁继续把代码执行完毕才会释放锁。 notifyAll()方法所有线程 void notify() 唤醒正在等待对象监视器的单个线程。 void notifyAll() 唤醒正在等待对象监视器的所有线程。 void wait() 导致当前线程等待直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。 注意wait()和notify()都需要synchronized中调用。 因为wait()就是用来释放锁的线程必须拥有该对象的锁才能去释放锁。 package com.day17.thread9;public class WaitDemo01 implements Runnable{int count0;Overridepublic void run() {while (count10){synchronized (ThreadWait.obj){//线程第一次进来没有线程等待不需要执行唤醒if (count!0){javaThreadWait.obj.notify();}System.out.println(Acount);try {ThreadWait.obj.wait();} catch (InterruptedException e) {e.printStackTrace();}count;}}} } package com.day17.thread9;public class WaitDemo02 implements Runnable{int count0;Overridepublic void run() {while (count10){synchronized (ThreadWait.obj){//唤醒线程1唤醒之后会继续执行当前代码//代码执行完才会释放锁ThreadWait.obj.notify();System.out.println(Bcount);//当程序运行到9表示循环结束了不需要再等待了if (count ! 9){try {ThreadWait.obj.wait();} catch (InterruptedException e) {e.printStackTrace();}}count;}}} } package com.day17.thread9;public class ThreadWait {//创建一个对象public static final Object obj new Object();public static void main(String[] args) {new Thread(new WaitDemo01()).start();new Thread(new WaitDemo02()).start();} } 【面试题】wait()和sleep()的区别 相同点都可以让线程暂停进入阻塞状态。 不同点 1.所属类不同wait()方法属于Object类的一个方法sleep()是属于Thread类的一个方法。 2.锁释放不同wait()会释放锁sleep()不会。 3.用途不同wait()常被用于线程间的交互通信sleep()一般用来暂停线程的执行。 4.用法不同wait()方法被调用线程不会自动苏醒需要别的线程调用同一个对象上的notify()方法或者notifyAll()方法进行唤醒操作如果调用wait(long timeout) 超时后会自动唤醒。 sleep()执行完之后线程会自动苏醒。 生产消费者模型基于wait方法的一个应用模型 不是面向对象的设计模式 也可以称为生产者 - 消费者 - 仓库模型 1.生产者在仓库未存满的时候开始生产商品仓库满了停止生产 2.消费者在仓库有产品的时候才能消费仓库空了则等待 3.当消费者发现仓库没有产品会通知生产者生产 4.当生产者生产可以消费的产品则通知消费者消费。 这个模型有哪些类 生产者就有生产方法 消费者具有消费方法 仓库添加产品减少产品 产品 package com.day17.thread10; //炸鸡产品 public class Chicken {int number;public Chicken(int number) {this.number number;}} package com.day17.thread10; //仓库 public class Warehouse {//表示仓库中最多可以被存放多少个产品Chicken[] chickens new Chicken[10];//计数变量用来记录产品数量int num0;//取出产品public synchronized Chicken pop() {//如果仓库中没有产品消费者等待while (num0){try {this.wait();//消费者等待} catch (InterruptedException e) {e.printStackTrace();}}num--;try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}Chicken chicken chickens[num];this.notifyAll();return chicken;}//添加产品public synchronized void put(Chicken chicken) {//如果产品满了不生产等待消费while (num chickens.length-1){try {this.wait();//停止生产等待消费} catch (InterruptedException e) {e.printStackTrace();}}//产品没满就通知生产者生产chickens[num] chicken;num;this.notifyAll();}} package com.day17.thread10; //生产者 public class Producer implements Runnable{//声明一个仓库对象通过仓库对象调用方法Warehouse warehouse new Warehouse();public Producer(Warehouse warehouse) {this.warehouse warehouse;}//生产方法Overridepublic void run() {for (int i 1; i 50; i) {//生产产品其实是在调用仓库对象往仓库中添加产品warehouse.put(new Chicken(i));System.out.println(生产者生产了第 i 号炸鸡);}}} package com.day17.thread10; //消费者 public class Consumer implements Runnable{//声明一个仓库对象通过仓库对象调用方法Warehouse warehouse new Warehouse();public Consumer(Warehouse warehouse) {this.warehouse warehouse;}//取出方法Overridepublic void run() {for (int i 1; i 50; i) {//消费产品其实是在调用仓库对象从仓库中取出产品Chicken chicken warehouse.pop();System.out.println(消费者消费了了第 chicken.number 号炸鸡);}} } package com.day17.thread10;public class Test {public static void main(String[] args) {Warehouse warehouse new Warehouse();new Thread(new Producer(warehouse)).start();new Thread(new Consumer(warehouse)).start();} }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/89123.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

做内贸什么网站资源比较多晒豆网站建设

教育 -森林植物识别技术 ——珍稀植物识别-章节资料考试资料-南京森林警察学院【】 单元测试一 1、【多选题】根据《最高人民法院关于审理破坏森林资源刑事案件具体应用法律若干问题的解释》规定,珍贵树木包括 A、列入《野生药材资源保护管理条例》中的植物 B、列入…

网站优化大赛陕西省建设厅便民服务网站

在MES项目实施过程中,经常会碰到工控机和电脑的选型问题,那么他们的区别是什么? 1、控机和普通个人电脑(PC)相比,具有以下几个区别: 1.运行环境不同:工控机通常需要在各种恶劣的工业环境中运行,如高温、高湿、强电磁干扰等,因此需要具有防尘、防水、抗干扰等特点。而…

新建的网站 找不到了开一个网站需要多少钱

Hudi,这个近年来备受瞩目的数据存储解决方案,无疑是大数据领域的一颗耀眼新星。其凭借出色的性能和稳定性,以及对于数据湖场景的深度适配,赢得了众多企业和开发者的青睐。然而,正如任何一项新兴技术,Hudi在…

谷歌在线搜索免费seo教程资源

1.判断有无注入点; and 11 and 12 2.猜表一般的表的名称无非是admin adminuser user pass password 等..and 0<>(select count(*) from *)and 0<>(select count(*) from admin) ---判断是否存在admin这张表3.猜帐号数目 如果遇到0< 返回正确页面 1<返回错误页…

中国网站设计公司网站首页轮播图怎么做

Unix网络编程是针对类Unix操作系统&#xff08;包括Linux、BSD以及其他遵循POSIX标准的操作系统&#xff09;进行网络通信开发的技术领域。网络编程涉及创建和管理网络连接、交换数据以及处理不同层次网络协议栈上的各种网络事件。在Unix环境中&#xff0c;网络编程通常涉及到以…

企业网站系统的设计与开发怎样在网上卖东西步骤

Hello&#xff0c;我是小恒不会java 最近学习django&#xff0c;写了一个demo,学到了不少东西。 我在GitHub上开源了&#xff0c;提示‘自行查看代码&#xff0c;维护&#xff0c;运行’。 最近有事&#xff0c;先发布代码了&#xff0c;我就随缘维护更新吧 介绍&#xff1a; 定…

怎么给网站做开场动画宁波企业制作网站

在数字化时代&#xff0c;信息的快速获取和高效整理变得尤为重要。微信公众号作为信息传播的重要平台&#xff0c;其内容经常需要被转换成更易于编辑和存档的格式&#xff0c;如Word文档。这里&#xff0c;我们将介绍如何利用“微附件”小程序实现这一过程&#xff0c;并分享一…

烟台网站搜索优化想买手表在哪个网站买是正品

诸多预测认为&#xff0c;2024 年将成为国内大模型产业应用爆发的元年。中关村科金作为领先的对话式 AI 技术解决方案提供商&#xff0c;自主研发的智能陪练产品&#xff0c;以学、练、考、培一体化的方式&#xff0c;为企业提供全方位的综合培训服务。 借助大模型技术方面的突…

公司设计网站多少钱电商运营推广怎么做

jboss8日志级别设置是否在寻找一种简单的方法来宣传&#xff0c;展示或演示使用JBoss业务规则管理系统&#xff08;BRMS&#xff09;产品的入门难度&#xff1f; 别无所求&#xff0c;因为我们已经召集了这个研讨会&#xff0c;因此您可以围绕JBoss BRMS构建一个晚上&#xff…

重庆招聘网官方网站大庆做网站比较好的公司

iPhone 拥有巨大的存储容量。您可以在 iPhone 设备上存储图像、文档和视频等数据。有时&#xff0c;您的 iPhone 会发生许多意外事件&#xff0c;例如意外删除&#xff0c;从而导致数据丢失。这里有 11 个最好的免费 iPhone 数据恢复软件&#xff0c;您可以免费下载&#xff0c…

求个没封的w站2022wordpress手机页面底部导航

一、工厂方法模式&#xff08;Factory Method&#xff09; 工厂方法模式有三种 1、普通工厂模式&#xff1a;就是建立一个工厂类&#xff0c;对实现了同一接口的一些类进行实例的创建。首先看下关系图&#xff1a; 举例如下&#xff1a;&#xff08;我们举一个发送邮件和短信的…

苏州网站建设制作工作室成都关键词

boot程序的主要功能是引导vxworks 内核,所以boot程序需要知道vxworks的内核存放在何处&#xff0c;通过什么手段去获取。在vxworks缺省的boot程序里有一条内建的default boot line,它指明了获得vxworks内核的途径&#xff0c;在boot程序启动时&#xff0c;它先寻找NVRAM里面有无…

商业网站开发模式外贸公司取名字参考大全

用途 字符匹配 语法 常用元字符 []    区间范围框 枚举值  [a-z0-9A-Z_] |    分枝条件或 \    特殊转义符&#xff08;取消转义&#xff09; \W [^A-Za-z0-9_] [\r\n] 换行符匹配 [\u4e00-\u9fa5] 汉字 [\s\S] 任意字符 限定符 贪婪匹配&…

网站安全狗卸载卸载不掉网页与网站设计

简介 在HTTP协议中&#xff0c;与get请求把请求参数直接放在url中不同&#xff0c;post请求的请求数据需通过消息主体(request body)中传递。 且协议中并没有规定post请求的请求数据必须使用什么样的编码方式&#xff0c;所以其请求数据可以有不同的编码方式&#xff0c;服务…

外国做动漫图片的网站叫什么潮汕网站建设

1. 前言 本文的目的&#xff0c;是帮助大家快速理解掌握Backbone的使用&#xff0c;但它并不是API&#xff0c;因此我不会将每一个方法都详细地描述&#xff0c;但是我会告诉你如何学习它们。 这是一篇稍稍较长的技术文章&#xff0c;因为我想将我所了解的东西尽可能详细地分享…

知名的网站建设公司杭州网络公司有哪些

摘要 二十一世纪是信息技术的时代,计算机已经应用到了各行各业中。采用计算机信息管理技术,可以有效的降低企业的管理成本,提高企业内部的工作效率。 本文从天天宾馆客房客房管理的一般流程出发,设计了一套天天宾馆客房管理信息系统,它可以管理天天宾馆客房中所有的客房的…

怎么登录百度app响应式网站做seo怎么样

文章目录 正则表达式概述使用场景不同环境下的正则表达式范例Linux (使用grep命令)Java (使用Pattern和Matcher类)Python (使用re模块) 正则表达式概述 正则表达式&#xff08;Regular Expression&#xff0c;简称regex或regexp&#xff09;是一种强大的文本处理工具&#xff…

做淘宝首页初学ps视频网站免费域名查询

以下源码基于rocketmq-spring-boot-start 2.1.1版本&#xff0c;其它版本可能会有差异 一. 前言 当我们在Spring Boot项目中集成RocketMQ后&#xff0c;只需要在配置文件(application.yml)中添加rocketmq的相关配置&#xff0c;即可使用rocketMQTemplate发送对象消息。登录Ro…

北京网站建设公司服务有哪些自适应网站开发资源

概述 目前代码比较少&#xff0c;写在一个文件中还体现不出什么缺点&#xff0c;但是随着代码量越来越多&#xff0c; 代码就越来越难以维护 为了解决难以维护的问题&#xff0c;我们把很多相似功能的函数分组&#xff0c;分别放到不同的文件中取。这样每个文件所包含的内容相…

国外域名购买网站如何建一个营销网站

大家好&#xff0c;我是若川。说起 Serverless&#xff0c;我想你应该并不陌生&#xff0c;作为一种云开发的架构模式&#xff0c;在近两年里&#xff0c;伴随着云原生概念的推广愈发火爆。作为一名 Serverless 的拥趸&#xff0c;在跟大家推荐的过程中&#xff0c;我经常能看到…