当前位置: 首页 > news >正文

东莞视频网站制作优化大师官网下载

东莞视频网站制作,优化大师官网下载,做网站高校视频,如何自建网站 卖东西进程 进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。每一个进程都有他自己的内存空间和系统资源 多进程意义在于计算机可以执行多个任务,提高cpu使用率 我们在一边玩游戏,一边听音乐的时候,是cpu在做着程序间的高…

进程

进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。每一个进程都有他自己的内存空间和系统资源
多进程意义在于计算机可以执行多个任务,提高cpu使用率
我们在一边玩游戏,一边听音乐的时候,是cpu在做着程序间的高效切换让我们觉得是同时进行的
注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。 如果是模拟出来的多线程,即在一个cpu的情况下,在同一时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉

线程

线程是依赖于进程而存在的,在一个进程内又可以执行多个任务,而这每个任务我就可以看出是一个线程
线程:是程序的执行单元,执行路径。是程序使用cpu的最基本单位。
单线程:程序只有一条执行路径
多线程:程序有多条执行路径
多线程意义在于提高应用程序的使用率。不是提高程序的执行速度
程序的执行其实都是在抢cpu的资源,cpu的执行权
多个进程是抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到cpu的执行权,所以线程的执行有随机性
注意:
并行和并发的区别:
前者:逻辑上同时发生,指在某一个时间段同时运行多个程序
CPU多核,多个线程可以同时执行线程池
后者:物理上同时发生,指在某一个时间点同时运行多个程序
CPU单核,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉
并发编程本质就是充分利用CPU的资源

java程序的运行原理

由java命令启动jvm,jvm启动就相当于启动了一个进程,接着有这个该进程创建了一个主线程去调用main()方法
那么jvm虚拟机的启动是多线程,因为垃圾回收线程也要先启动,否则很容易出现内存溢出。主线程加垃圾回收线程
小结:
线程就是独立的执行路径;
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
main()成为主线程,为系统的入口,用于执行整个程序;
在一个进程中,如果开辟了多个线程,线程的运行由调度器(CPU)安排调度,调度器是与操作系统紧密相关,先后顺序是不能人为的干预的;
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
线程会带来额外的开销,如CPU调度时间,并发控制开销;
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;

如何实现多线程的程序?

继承Thread类:
子类继承Thread类具备多线程能力
启动线程:子类对象.start()方法
不建议使用:避免OOP单继承局限性

import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;
import java.net.URL;public class ThrendDemo extends Thread{//src="http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191101021614.png"//src="http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20201015024451.png"//src="http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20190902094518.png"String url;String name;public ThrendDemo(String url,String name){this.url=url;this.name=name;}@Overridepublic void run() {DownWeb downWeb = new DownWeb();downWeb.downLoader(url,name);System.out.println("下载了文件名为"+name);}public static void main(String[] args) {ThrendDemo th1 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191101021614.png","1.jpg");ThrendDemo th2 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20201015024451.png","2.jpg");ThrendDemo th3 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20190902094518.png","3.jpg");th1.start();th2.start();th3.start();}
}class DownWeb{public void downLoader(String url,String name) {try{FileUtils.copyURLToFile(new URL(url),new File(name));}catch (IOException e) {e.printStackTrace();System.out.println("IO异常,下载失败");}}}

另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动
实现接口方式的好处
可以避免由于java单继承带来的局限性;适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想
为什么要重写run()方法?
run()里面封装的是被线程执行的代码
启动线程对象用的是哪个方法?
start()
run()和start()方法的区别?
run()直接调用的仅仅是普通方法
start()先启动线程,再由jvm调用run()
实现接口Runnable具有多线程能力
启动线程:new Thread(传入目标对象).start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;
import java.net.URL;public class ThrendDemo implements Runnable{String url;String name;public ThrendDemo(String url,String name){this.url=url;this.name=name;}@Overridepublic void run() {DownWeb downWeb = new DownWeb();downWeb.downLoader(url,name);System.out.println("下载了文件名为"+name);}public static void main(String[] args) {ThrendDemo th1 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20200528052009.png","4.jpg");ThrendDemo th2 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191105020544.png","5.jpg");ThrendDemo th3 = new ThrendDemo("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1603600907&di=62c16889d83b7e6742012de55df48d04&src=http://meitu.qqzong.com/www.52520qq.com/uploads/allimg/181106/003G51110-0.jpg","6.jpg");//        th1.start();
//        th2.start();
//        th3.start();new Thread(th1).start();new Thread(th2).start();new Thread(th3).start();}
}class DownWeb{public void downLoader(String url,String name) {try{FileUtils.copyURLToFile(new URL(url),new File(name));}catch (IOException e) {e.printStackTrace();System.out.println("IO异常,下载失败");}}}

实现Callable接口
1.实现Callable接口,需要返回值类型
2.重写call方法,需要抛出异常
3.创建目标对象
4.创建执行服务:
5.提交执行
6.获取结果
7.关闭服务

import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;public class ThrendDemo implements Callable<Boolean> {String url;String name;public ThrendDemo(String url,String name){this.url=url;this.name=name;}public static void main(String[] args) throws ExecutionException, InterruptedException {ThrendDemo th1 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20200528052009.png","4.jpg");ThrendDemo th2 = new ThrendDemo("http://iflyssedata.oss-cn-shanghai.aliyuncs.com/images/20191105020544.png","5.jpg");ThrendDemo th3 = new ThrendDemo("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1603600907&di=62c16889d83b7e6742012de55df48d04&src=http://meitu.qqzong.com/www.52520qq.com/uploads/allimg/181106/003G51110-0.jpg","6.jpg");
//        4.创建执行服务:ExecutorService executorService =Executors.newFixedThreadPool(3);
//        5.提交执行Future<Boolean> future1= executorService.submit(th1);Future<Boolean> future2= executorService.submit(th2);Future<Boolean> future3= executorService.submit(th3);
//        6.获取结果future1.get();future2.get();future3.get();
//        7.关闭服务executorService.shutdownNow();}@Overridepublic Boolean call() throws Exception {DownWeb downWeb = new DownWeb();downWeb.downLoader(url,name);System.out.println("下载文件名为"+name);return true;}
}
class DownWeb{public void downLoader(String url,String name) {try{FileUtils.copyURLToFile(new URL(url),new File(name));}catch (IOException e) {e.printStackTrace();System.out.println("IO异常,下载失败");}}
}

匿名内部类(重写run)

 Thread thread = new Thread(new Runnable() {public void run() {}});thread.start();

由于线程是依赖进程而存在,所以应该先创建一个进程出来,而进程是系统创建的,所以我们应该去调用系统功能创建一个进程。java是不能直接调用系统功能的,依赖于c/c++去调用系统功能创建进程,然后java去调用这样的东西
(Unsafe类 java无法操作内存,java可以调用c++ native c++可以操作内存)
(1)如何设置线程对象的名称?
public final String getName();获取线程的名称

@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<200;i++) {System.out.println(getName()+"点赞"+i);}}
Thread-0点赞0
Thread-0点赞1
Thread-0点赞2
Thread-0点赞3
Thread-0点赞4
Thread-1点赞0

(2)如何设置线程对象的名称
public final void setName(String name)

//默认无参构造+setName()来设置线程名称
//		//创建两个线程对象
//		MyThreadDemo myThreadDemo1 = new MyThreadDemo();
//		MyThreadDemo myThreadDemo2 = new MyThreadDemo();
//		//设置线程名称myThreadDemo1.setName("线程一");myThreadDemo2.setName("线程二");
//		//线程启动
//		myThreadDemo1.start();
//		myThreadDemo2.start();//通过有参构造来设置线程名称MyThreadDemo myThreadDemo3 =new MyThreadDemo("线程三");MyThreadDemo myThreadDemo4 = new MyThreadDemo("线程四");myThreadDemo3.start();myThreadDemo4.start();线程二点赞9
线程一点赞0
线程一点赞1
线程一点赞2
线程一点赞3

针对不是Thread类的子类中来获取线程对象的名称?
public static Thread currentThread()
Thread.currentThread().getName()
(3)线程有个默认优先级就是5
如何设置优先级?(1最低优先级,10最高优先级,优先级用数字表示,范围从1~10)
java使用的是抢占式调度模型 优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的cpu时间片相对多一些
线程优先级高仅仅表示线程获取的cpu时间片的几率高,但是要在运行次数多的时候才会看到比较好的效果
public final int getPriority();返回线程对象的优先级
public final void setPriority(int newPriority)//更改线程的优先级
注意:优先级的设定建议在start()调度前;优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看cpu的调度

public class ThreadPriority implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());}public static void main(String[] args) {ThreadPriority threadPriority = new ThreadPriority();Thread thread1 = new Thread(threadPriority);Thread thread2 = new Thread(threadPriority);Thread thread3 = new Thread(threadPriority);Thread thread4= new Thread(threadPriority);Thread thread5= new Thread(threadPriority);Thread thread6 = new Thread(threadPriority);thread1.setPriority(8);thread1.start();thread2.setPriority(5);thread2.start();thread4.setPriority(7);thread4.start();thread6.setPriority(Thread.MAX_PRIORITY);thread6.start();}
}

线程的休眠
public static void sleep(long mills)毫秒数
时间达到后线程进入就绪状态;
可以模拟网络延时(放大问题的发生性),倒计时等;
每一个对象都有一个锁,sleep不会释放锁;
线程的加入
public final void join()
Join合并线程,待此线程执行完成后,在执行其他线程,其他线程阻塞;
可以想象成插队

	public class ThreadJoin implements Runnable{@Overridepublic void run() {for(int i=0;i<50;i++){System.out.println("线程-->"+i);}}public static void main(String[] args) throws InterruptedException {ThreadJoin threadJoin = new ThreadJoin();Thread t = new Thread(threadJoin);t.start();for(int i=0;i<20;i++){System.out.println("主线程-->"+i);if(i==10){t.join();}}}
}

线程礼让
public static void yield()
让多个线程执行和谐一点,但是不能保证一人一次
让当前正在执行的线程暂停,但不阻塞;
将线程从运行状态转化为就绪状态;
让cpu重新调度,礼让不一定成功,看cpu心情
后台线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕;
虚拟机不用等待守护线程执行完毕;
如:后台记录操作日志,监控内存,垃圾回收等待
public final void setDaemon(boolean on)线程启动前必须调用此方法。

public class TestDaemon {public static void main(String[] args) {he h = new he();Thread thread = new Thread(h);thread.setDaemon(true);thread.start();new Thread(new my()).start();}
}
class my implements Runnable{@Overridepublic void run() {for (int i = 0; i < 8; i++) {System.out.println("自己的线程");}}
}class he implements Runnable{@Overridepublic void run() {while(true){System.out.println("守护线程");}}
}

中断线程
public final void stop():已过时,比较暴力
public void interrupt():中断线程,把线程的状态终止,并抛出一个InterruptedException
如何让线程停止?(设置标志位)

public class ThreadStop implements Runnable{boolean flage = true;@Overridepublic void run() {int i=0;while(flage){System.out.println(Thread.currentThread().getName()+"-->"+(i++));}}public void StopThread(){this.flage = false;}public static void main(String[] args) {ThreadStop threadStop = new ThreadStop();new Thread(threadStop).start();for(int i=0;i<20;i++){System.out.println(Thread.currentThread().getName()+i);if(i==10){threadStop.StopThread();System.out.println("线程停止了");}}}
}

多线程实例

并发:同一个对象被多个线程同时操作
线程同步:
由于同一个进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可,存在以下问题:
一个线程持有锁会导致其他所有需要此锁的线程挂起;
在多线程竞争下,加锁,释放锁会导致比较多的上下问切换和调度延时,引起性能问题;
如果一个优先级高的线程等待一个优先级低的线程释放锁 会导致优先级倒置,引起性能问题
举例:100张票,3个售票窗口,设计一个程序模拟电影院售票
会出现哪些问题:相同的票出现多次:
cpu的一次操作必须是原子性
出现负数的票:
随机性和延迟导致的
注意:线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响比较大

引起一个程序是否有线程安全问题的标准?
a.是否多线程环境
b.是否有共享数据
c.是否有多条语句操作共享数据
满足这些条件,会出现线程安全问题,如何解决?
同步机制(同步代码块:)
synchronized(Obj对象){
需要同步的代码;(多条语句操作共享数据的代码块)
}

Obj称为同步监视器
Obj可以是任何对象,但是推荐使用共享资源作为同步监视器
同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this(对象本身或者class)
同步监视器的执行过程:
1.第一个线程访问,锁定同步监视器,执行其中代码
2.第二个线程访问,发现同步监视器被锁定,无法访问
3.第一个线程访问完毕,解锁同步监视器
4.第二个线程访问,发现同步监视器没有锁,然后锁定并访问
注意:同步可以解决线程安全问题的根本原因就在那个对象上。该对象如同锁的功能,多个线程必须是同一把锁

 public static void main(String[] args) throws InterruptedException {List<String > list = new ArrayList<String>();for(int i=0;i<10000;i++){new Thread(()->{synchronized (list) {list.add(Thread.currentThread().getName());}}).start();}Thread.sleep(1000);System.out.println(list.size());}10000

虽然同步解决了多线程的安全问题,但是每当线程相当多的时候,每个线程都会去判断同步上的锁,耗资源,降低了程序运行的效率
同步代码块的锁及同步方法应用锁的问题
同步代码块的所对象是谁?
任意对象(锁的对象就是变化的量,需要增删改)

同步方法的格式及锁对象问题?
把同步关键字加在方法上
同步方法是this
静态方法及锁对象问题?
静态方法的锁对象是谁类的字节码文件对象
为了更清晰的表达如何加锁和释放锁,用
Lock:
void lock()//加锁
void unlock();//释放锁
ReentrantLock是实现Lockde 实现类
综合代码如下:

public class MyThread implements Runnable{private int toe = 100;//定义锁private Lock lock= new ReentrantLock();@Overridepublic  void run() {// TODO Auto-generated method stubwhile(true) {lock.lock();if(toe>0) {try {Thread.sleep(100);						System.out.println(Thread.currentThread().getName()+"正在出售"+(toe--)+"票");} catch (InterruptedException e) {e.printStackTrace();}			finally {lock.unlock();}}}public static void main(String[] args) {MyThread myThread = new MyThread();Thread th1 = new Thread(myThread, "窗口一");Thread th2 = new Thread(myThread, "窗口二");Thread th3 = new Thread(myThread, "窗口三");th1.start();th2.start();th3.start();}
}

死锁问题

同步弊端:效率低,如果出现了同步嵌套,就容易产生死锁问题
死锁:是指多个线程在执行的过程中,因争夺资源产生的一种互相等待现象
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能进行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,某一个同步代码块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题
死锁的四个必要条件:
1、互斥条件:一个资源每次只能被一个进程使用
2、请求与保持条件:一个进程因请求资源而被阻塞时,对方已获得的资源保持不放
3、不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
synchronized与lock的对比:
1、Lock是显示锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放
2、Lock只有代码块锁,synchronized有代码块锁和方法锁
3、使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
4、优先级使用顺序:
Lock>同步代码块(已经进入方法体,分配了相应资源)>同步方法(在方法体之外)

死锁排查

public class DeadLock {public static void main(String[] args) {new Thread(new MyThread("la","lb")).start();new Thread(new MyThread("lb","la")).start();}
}
class MyThread implements Runnable{String lockA;String lockB;public  MyThread(String lockA,String lockB){this.lockA=lockA;this.lockB=lockB;}@Overridepublic void run() {synchronized(lockA){System.out.println(Thread.currentThread().getName()+"A去拿B的资源");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockB){System.out.println(Thread.currentThread().getName()+"B去拿A的资源");}}}
}

jps -l来查看进程号:
5328 sun.tools.jps.Jps
16296
5640 com.qianjiang.item.lock.DeadLock
14620 org.jetbrains.jps.cmdline.Launcher
jstack 进程号 来查看具体信息

"Thread-1" #13 prio=5 os_prio=0 tid=0x000000001a4fa800 nid=0x22c8 waiting for monitor entry [0x000000001b2ff000]java.lang.Thread.State: BLOCKED (on object monitor)at com.qianjiang.item.lock.MyThread.run(DeadLock.java:31)- waiting to lock <0x00000000d60c1358> (a java.lang.String)- locked <0x00000000d60c1388> (a java.lang.String)at java.lang.Thread.run(Thread.java:748)"Thread-0" #12 prio=5 os_prio=0 tid=0x000000001a4f7800 nid=0x2860 waiting for monitor entry [0x000000001b1ff000]java.lang.Thread.State: BLOCKED (on object monitor)at com.qianjiang.item.lock.MyThread.run(DeadLock.java:31)- waiting to lock <0x00000000d60c1388> (a java.lang.String)- locked <0x00000000d60c1358> (a java.lang.String)at java.lang.Thread.run(Thread.java:748)

排查问题:
1、日志信息
2、堆栈信息

生产者和消费者问题(线程协作)

cpu的一点点时间片的执行权,就足够执行很多次
线程运行的随机性
这样出现了线程安全问题,解决它用加锁
加锁注意的是不同种类的线程都要加锁,不同种类的线程加的锁必须是同一把(操作的是同一个对象)
这样线程安全解决了,会存在着如下问题:
a.假设消费者先抢到cpu的执行权,就会去消费数据,但是现在的数据时没有或者默认值,无意义,等着生产者去生产数据,再消费
b.假设生产者先抢到cpu的执行权,就会去产生数据,产生完成,继续产生数据是有问题,应该等着消费者把数据消费掉,然后在生产
生产者:
先看是否有数据,有就等待,没有就生产,生产完之后通知消费者来消费
消费者:
先看是否有数据,有就消费,没有就等待通知生产者生产数据
在生产者消费者问题中,仅有synchronized是不够的:
synchronized可阻止并发更新同一个共享资源,实现了同步
synchronized不能用来实现不同线程之间的消息传递(通信)
解决这个问题,java就提供了一种机制,等待唤醒机制
Object类中提供了三个方法:
wait();等待,从这里等待就从这里醒来,等待过程就立即释放锁了与sleep不同,会释放锁
notify():唤醒单个进程,并不代表立马可以执行 ,必须还得抢占cpu的执行权
notifyAll():唤醒所有线程
为什么这些方法存在Object类中而不是Thread类中?
这些方法的调用必须通过锁对象,而使用的锁对象是任意锁对象

线程组

就是把多个线程组合在一起,可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制
默认情况下:所有的线程都属于同一个组

ThreadGroup threadGroup = new ThreadGroup("这是一个线程组");ThreadGroupDemo threadGroupDemo = new ThreadGroupDemo();Thread t1 = new Thread(threadGroup,threadGroupDemo,"线程一");Thread t2= new Thread(threadGroup,threadGroupDemo,"线程二");System.out.println(t1.getName());//线程一System.out.println(t2.getName());//线程二System.out.println(threadGroup.getName());//这是一个线程组

线程池

程序启动一个新的线程成本计较高,因为它涉及要与操作系统交互。线程池可以很好地提高性能,尤其是当程序中要创建大量生存期很短的线程时,考虑使用线程池
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用,从jdk5开始,java内置支持线程池
创建新的线程池:public static ExecutorService newFixedThreadPool(int nThreads)
调用方法:
Future<?> submit(Runnable task)提交一个可运行的任务执行,并返回一个表示该任务的未来
Future submit(Callable task)
结束:
void shutdown()启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。 如果已经关闭,调用没有额外的作用。
此方法不等待以前提交的任务完成执行。 使用awaitTermination做到这一点。

        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);ThreadGroupDemo myThread = new ThreadGroupDemo();ThreadGroupDemo myThread1 = new ThreadGroupDemo();Future<?> submit = newFixedThreadPool.submit(myThread);Future<?> submit2 = newFixedThreadPool.submit(myThread1);newFixedThreadPool.shutdown();

定时器

是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台的线程方式执行
Time类:
void schedule(TimerTask task, long delay) 在指定的延迟之后安排指定的任务执行。
void schedule(TimerTask task, long delay, long period) 在指定 的延迟之后开始 ,重新执行 固定延迟执行的指定任务。
TimeTask类:
boolean cancel()
取消此计时器任务。
abstract void run()
该定时器任务要执行的操作。
开发中Quartz是一个完全由java编写的开源框架

public class TimerDemo {public static void main(String[] args) {//创建一个定时器Timer time = new Timer();//开启定时器做任务System.out.println(new Date());time.schedule(new myTask(time), 8000);}
}
class myTask extends TimerTask{Timer time;public myTask(Timer time) {this.time=time;}@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("炸弹响起来!!");time.cancel();System.out.println(new Date());}}
* 在指定的时间删除我们指定目录
*/
public class DeleteFolder extends TimerTask{Timer t;public DeleteFolder(Timer t) {// TODO Auto-generated constructor stubthis.t = t;}@Overridepublic void run() {// TODO Auto-generated method stubFile file = new File("demo");DeleteFile(file);t.cancel();}private void DeleteFile(File file) {// TODO Auto-generated method stub//用递归方法删除目录File[] listFiles = file.listFiles();if(listFiles!=null) {for(File f:listFiles) {if(f.isDirectory()) {DeleteFile(f);}else {System.out.println(f.getName()+":"+f.delete());}}System.out.println(file.getName()+":"+file.delete());}}}
public class MyTimer {public static void main(String[] args) throws Exception {Timer t = new Timer();String s= "2020-9-17 10:22:00";SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d = simpleDateFormat.parse(s);t.schedule(new DeleteFolder(t), d);}}

以前线程安全类的回顾

StringBuffer sb = new StringBuffer();
Vector<String> v = new Vector<String>();
Hashtable<String,String> ht = new Hashtable<String,String>();Vector是线程安全的时候才去考虑他,也可以不用
用public static<T> List<T> synchronizeList(List<T> list)
List<String> list1 = new ArrayList<String>();//线程不安全
List<String> list2 = Collections.synchronizedList(new ArrayList<String>())

线程的生命周期

新建:创建线程对象
就绪:有执行资格,没有执行权(调用start方法,线程立即进入就绪状态,但不意味着立即调度执行)
运行:有执行资格,有执行权(线程才真正执行线程体的代码块 )
阻塞:由于一些操作让线程处于该状态,没有执行资格,没有执行权
而另一些操作却可以把它给激活,激活后处于就绪状态(当调用sleep,wait或者同步锁定时,线程进入阻塞状态,就是代码不往下执行,阻塞事件解除后,重新进入就绪状态,等待cpu调度执行)
死亡:线程对象变成垃圾,等待被回收,中断或者结束 就不能再次启动了

public class ThreadStat {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for(int i=0;i<5;i++){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("-------");});Thread.State s =  thread.getState();System.out.println(s);//NEW//启动线程thread.start();s=thread.getState();System.out.println(s);//RUNNABLE//阻塞状态while(s!=Thread.State.TERMINATED){//线程不终止Thread.sleep(1000);s=thread.getState();System.out.println( s);}}
}
NEW
RUNNABLE
TIMED_WAITING
TIMED_WAITING
RUNNABLE
TIMED_WAITING
RUNNABLE
-------
TERMINATED

JUC的学习

常用工具类:
java.util.concurrent.CyclicBarrier
允许一组线程全部等待彼此达到共同屏障点的同步辅助(加法计数器)

public class CyclicBarrierDemo {public static void main(String[] args) {int parties=5;CyclicBarrier cyclicBarrier = new CyclicBarrier(parties,()->{System.out.println("恭喜集全了"+parties+"福");});for(int i=1;i<=parties;i++){int temp = i;new Thread(()->{System.out.println("线程"+Thread.currentThread().getName()+"-->集"+temp+"福");try {cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}},String.valueOf(i)).start();}}
}

java.util.concurrent.CountDownLatch
一个CountDownLatch为一个计数的CountDownLatch用作一个简单的开/关锁存器,或者门:所有线程调用await在门口等待,直到被调用countDown()的线程打开
void countDown()
减少锁存器的计数,如果计数达到零,释放所有等待的线程。
void await() //等待计数器归零

public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {int count=6;CountDownLatch countDownLatch = new CountDownLatch(count);for (int i=1;i<=count;i++){new Thread(()->{System.out.println(Thread.currentThread().getName()+"-->go out");countDownLatch.countDown();//数量减一}).start();}countDownLatch.await();//等数量归零,继续执行下一步System.out.println("close door");}
}
Thread-0-->go out
Thread-2-->go out
Thread-1-->go out
Thread-3-->go out
Thread-5-->go out
Thread-4-->go out
close door

java.util.concurrent.Semaphore
一个计数信号量。 在概念上,信号量维持一组许可证。 如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它。 每个release()添加许可证,潜在地释放阻塞获取方
public void acquire()
throws InterruptedException从此信号量获取许可证
public void release()释放许可证,将其返回到信号量。

public class SemaphoreDemo {public static void main(String[] args) {//六个车位 抢占三个车位 限流int permits=3;Semaphore semaphore = new Semaphore(3);for(int i=1;i<=7;i++){new Thread(()->{try {semaphore.acquire();System.out.println(Thread.currentThread().getName()+"抢占了车位");TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"离开了车位");} catch (InterruptedException e) {e.printStackTrace();} finally {semaphore.release();}}).start();}}
}
Thread-1抢占了车位
Thread-2抢占了车位
Thread-0抢占了车位
Thread-2离开了车位
Thread-0离开了车位
Thread-3抢占了车位
Thread-1离开了车位
Thread-4抢占了车位
Thread-5抢占了车位
Thread-3离开了车位
Thread-6抢占了车位
Thread-5离开了车位
Thread-4离开了车位
Thread-6离开了车位

semaphore.acquire();获得 假设如果已经满了,等待,等待被释放为止
semaphore.release();释放,会将当前的信号量释放+1.然后唤醒等待的线程
作用:多个共享资源互斥的使用,并发限流,控制最大的线程数

读写锁

ReadWriteLock维护一对关联的locks ,一个用于只读操作,一个用于写入,所以:
读 读:可以共存
读 写 :不能共存
写 写:不能共存
Lock readLock()
返回用于阅读的锁。
Lock writeLock()
返回用于写入的锁。
独占锁(写锁):一次只能被一个线程占有
共享锁(共享锁):多个线程可以同时占有

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {public static void main(String[] args) {MyCache myCache = new MyCache();//写for(int i=0;i<5;i++){new Thread(()->{myCache.writer();}).start();}//读for(int i=0;i<2;i++){new Thread(()->{myCache.reader();}).start();}}
}
class MyCache{ReadWriteLock readWriteLock = new ReentrantReadWriteLock();//写public void writer(){try{readWriteLock.writeLock().lock();   System.out.println(Thread.currentThread().getName()+"--->开始写入");System.out.println("-----------写写写------");   System.out.println(Thread.currentThread().getName()+"-->写入完成");}finally {readWriteLock.writeLock().unlock();}}//读public void reader(){try{readWriteLock.readLock().lock();System.out.println(Thread.currentThread().getName()+"--->开始读");System.out.println("-----------读读读------");System.out.println(Thread.currentThread().getName()+"--->读出完成");}finally {readWriteLock.readLock().unlock();}}
}

(阻塞队列)BlockingDeque

这个队列排列元素FIFO(先进先出)。
public ArrayBlockingQueue(int capacity)创建具有给定(固定)容量capacity - 这个队列的容量
有返回值,不抛出异常
boolean offer(E e)入列
E poll()出列deque为空,则返回null

public class BlockingDequeDemo {public static void main(String[] args) {ArrayBlockingQueue blockingDeque = new ArrayBlockingQueue(2);System.out.println( blockingDeque.offer("A"));//trueSystem.out.println(blockingDeque.offer("B"));//trueSystem.out.println(blockingDeque.offer("C"));//falseSystem.out.println(blockingDeque.poll());//ASystem.out.println(blockingDeque.poll());//BSystem.out.println(blockingDeque.poll());//null}
}

超时等待
public boolean offer(E e,
long timeout,
TimeUnit unit)
throws InterruptedException在该队列的尾部插入指定的元素,等待指定的等待时间,以使空间在队列已满时变为可用。
e - 要添加的元素
timeout - 具体时间 (等待多久程序结束)
unit :时间单位

public class BlockingDequeDemo {public static void main(String[] args) throws InterruptedException {int capacity=2;ArrayBlockingQueue blockingDeque = new ArrayBlockingQueue(2);blockingDeque.offer("A");blockingDeque.offer("B");//blockingDeque.offer("C",3, TimeUnit.SECONDS);//三秒之后继续执行System.out.println("-------------");System.out.println(blockingDeque.poll());System.out.println(blockingDeque.poll());blockingDeque.poll(3,TimeUnit.SECONDS);}
}

一直等待
public void put(E e)
throws InterruptedException在该队列的尾部插入指定的元素,如果队列已满,则等待空间变为可用。存入元素,超过最大容量就一直都等待

public E take()
throws InterruptedException取出元素,对列中没有就一直等待

public class BlockingDequeDemo {public static void main(String[] args) throws InterruptedException {int capacity=2;ArrayBlockingQueue blockingDeque = new ArrayBlockingQueue(2);blockingDeque.put("A");blockingDeque.put("B");//blockingDeque.put("c");System.out.println("----------------");System.out.println(blockingDeque.take());System.out.println(blockingDeque.take());blockingDeque.take();}
}

SynchronousQueue(同步队列)

和BlockingDeque不一样,不保证容量大小。只放(put)一个值,并且放了就需要取(take)出来
void put(E e)
将指定的元素添加到此队列,等待另一个线程接收它。
E take() 取

线程池

Executor
线程池:三大方法 7大参数 4种拒绝策略
程序的运行 本质:占用系统的资源
为了优化资源的使用 引入线程池技术(池化技术)池化技术:事先准备好资源 用完了 在还给我
线程池、连接池、内存池、对象池。。。
线程池的好处:
降低资源的消耗
提高响应的速度
方便管理
线程管理 可以控制最大并发数 管理线程

public static void main(String[] args) {SynchronousQueue<Integer> synchronousQueue = new SynchronousQueue();new Thread(()->{try {synchronousQueue.put(23);System.out.println(Thread.currentThread().getName()+"put 23");synchronousQueue.put(13);System.out.println(Thread.currentThread().getName()+"put 13");synchronousQueue.put(93);System.out.println(Thread.currentThread().getName()+"put 93");} catch (InterruptedException e) {e.printStackTrace();}},"线程一").start();new Thread(()->{try {TimeUnit.SECONDS.sleep(2);System.out.println(Thread.currentThread().getName()+"-->take"+synchronousQueue.take());TimeUnit.SECONDS.sleep(2);             System.out.println(Thread.currentThread().getName()+"-->take"+synchronousQueue.take());TimeUnit.SECONDS.sleep(2);            System.out.println(Thread.currentThread().getName()+"-->take"+synchronousQueue.take());} catch (InterruptedException e) {e.printStackTrace();}},"线程二").start();}
 public static void main(String[] args) {//ExecutorService pool = Executors.newSingleThreadExecutor();//单个线程池//ExecutorService pools = Executors.newFixedThreadPool(5);//多个线程池ExecutorService threadPool = Executors.newCachedThreadPool();try{for(int i=0;i<10;i++){//线程池创建线程threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+" ok");});}}finally {//关闭线程池threadPool.shutdown();}}

线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

ThreadPoolExecutor的7大参数

  public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

corePoolSize:核心线程池大小
maxiumPoolSize:最大核心线程池大小
keepAliveTime:超时了没有调用就会释放
unit:超时单位
BlockingQueue:阻塞队列
threadFactory:线程工厂,创建线程的,一般不动
handle:拒绝策略
ThreadPoolExecutor四种拒绝策略
AbortPolicy:corePoolSize 满 BlockingQueue满 同时MaxiumPoolSize也用上了 (对列满了 如果还有其他人进来 不处理这个人了,抛出异常)
CallerRunsPolicy:队列满了 main线程有时会处理 不抛出异常
DiscardOldestPolicy :队列满了,尝试着处理,不会抛出异常
DiscardPolicy:队列满了 (有时候运行多了随缘处理)不处理进来的人,不会抛出异常

 public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,5,3,TimeUnit.SECONDS,new LinkedBlockingDeque<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());try{//最大承载量 max+capacity(8)for(int i=1;i<=12;i++){//线程池创建线程threadPoolExecutor .execute(()->{             System.out.println(Thread.currentThread().getName()+" ok");});}}finally {//关闭线程池threadPoolExecutor .shutdown();}}
}

maxiumPoolSize:最大核心线程池大小怎么定义?
1、CPU密集型 几核就定义几核,可以保持cpu的效率最高
可以将线程数设置为 N(CPU 核心数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。
怎么知道电脑是几核?

System.out.println(Runtime.getRuntime().availableProcessors());

2.io密集型:
设置大于程序中十分耗io的线程这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是 : 核心线程数=CPU核心数量*2。

ForkJoin

分治编程
它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。
如何使用forkjoin
1、forkjoinpool通过它执行
2、计算任务forkjoinpool.execute(ForkjoinTask task)
3、计算类要继承RecursiveTask
分治思想策略类:

public class ForkJoinDemo extends RecursiveTask<Long> {private Long start;private Long end;//临界值private Long temp = 100000L;public ForkJoinDemo(Long start,Long end){this.start =start;this.end=end;}@Overrideprotected Long compute() {//小于临界值 用普通方式求和if((end-start)<temp){Long sum =0L;for(Long i=start;i<=end;i++){sum+=i;}return sum;}else{long middle = (start+end)/2;ForkJoinDemo task1 = new ForkJoinDemo(start,middle);task1.fork();//拆分了任务,八任务压人线程队列ForkJoinDemo task2 = new ForkJoinDemo(middle+1,end);task2.fork();long result = task1.join()+task2.join();//对结果的统计return  result;}}
}

测试类:

public class ForkJoinTest {public static void main(String[] args) throws ExecutionException, InterruptedException {//test();//执行时间:8489test2();//执行时间:249}//使用Stream并行流private static void test2() {long start = System.currentTimeMillis();long sum =  LongStream.rangeClosed(0L,10_0000_0000).parallel().reduce(0,Long::sum);long end = System.currentTimeMillis();System.out.println("sum"+sum+"执行时间:"+(end-start));}//使用forkjoinprivate static void test() throws ExecutionException, InterruptedException {long start = System.currentTimeMillis();ForkJoinTask<Long> task = new ForkJoinDemo(0L,10_0000_0000L);ForkJoinPool forkJoinPool = new ForkJoinPool();ForkJoinTask<Long> submit = forkJoinPool.submit(task);//这样会足阻塞等待Long sum = submit.get();long end = System.currentTimeMillis();System.out.println("sum"+sum+"执行时间:"+(end-start));}
}

异步回调

Future
java.util.concurrent.CompletableFuture
异步方法的依赖完成提供的操作

  public static void main(String[] args) throws ExecutionException, InterruptedException {//类比于ajax中的成功和失败的回调//成功返回成功的信息,错误返回错误的信息CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getName());int i= 10/0;return 1024;});Integer completableFuture1 = completableFuture.whenComplete((t, u)->{System.out.println("t->"+t);//没错误,返回了成功的信息;有错误返回nullSystem.out.println("u->"+u);//没错误返回null,有错误返回错误的信息(java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero)}).exceptionally((e)->{System.out.println(e.getMessage());return 233;}).get();System.out.println(completableFuture1);//233}

JMM

jmm:java内存模型 不存在的东西,一种约定而已
关于jmm的一些同步的约定:
1、线程解锁前,必须把共享变量刷回主存
2、线程加锁前,必须读取主存中的最新值到工作内存中
3、加锁和解锁是同一把锁
问题:线程B修改了值,但是线程A不能及时可见

 private static  int num =0;public static void main(String[] args) {new Thread(()->{while(num==0){//这条线程对主存的变化不知道}}).start();int num=1;System.out.println(num);}

与工作内存之间的交互协议,即一个变量如何从主内存拷贝到工作内存。如何从工作内存同步到主内存中的实现细节。java内存模型定义了8种操作来完成。这8种操作每一种都是原子操作。8种操作如下:
lock(锁定):作用于主内存,它把一个变量标记为一条线程独占状态;
read(读取):作用于主内存,它把变量值从主内存传送到线程的工作内存中,以便随后的load动作使用;
load(载入):作用于工作内存,它把read操作的值放入工作内存中的变量副本中;
use(使用):作用于工作内存,它把工作内存中的值传递给执行引擎,每当虚拟机遇到一个需要使用这个变量的指令时候,将会执行这个动作;
assign(赋值):作用于工作内存,它把从执行引擎获取的值赋值给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时候,执行该操作;
store(存储):作用于工作内存,它把工作内存中的一个变量传送给主内存中,以备随后的write操作使用;
write(写入):作用于主内存,它把store传送值放到主内存中的变量中。
unlock(解锁):作用于主内存,它将一个处于锁定状态的变量释放出来,释放后的变量才能够被其他线程锁定;
Java内存模型还规定了执行上述8种基本操作时必须满足如下规则:
(1)不允许read和load、store和write操作之一单独出现(即不允许一个变量从主存读取了但是工作内存不接受,或者从工作内存发起会写了但是主存不接受的情况),以上两个操作必须按顺序执行,但没有保证必须连续执行,也就是说,read与load之间、store与write之间是可插入其他指令的。
(2)不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
(3)不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中。
(4)一个新的变量只能从主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
(5)一个变量在同一个时刻只允许一条线程对其执行lock操作,但lock操作可以被同一个条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。
(6)如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
(7)如果一个变量实现没有被lock操作锁定,则不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量。
(8)对一个变量执行unlock操作之前,必须先把此变量同步回主内存(执行store和write操作)。

Volatile

就是因为在jmm中问题:线程B修改了值,但是线程A不能及时可见,所以引入volatile机制
volatile是java虚拟机提供的轻量级同步机制
1、保证可见性

 private volatile static  int num =0;//加了volatile时保证了可见性public static void main(String[] args) {new Thread(()->{//这个时候不会陷入死循环的while(num==0){}}).start();num=1;System.out.println(num);}

2、不保证原子性
那怎么保证原子性呢?(synchronized lock)
java.util.concurrent.atomic.AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;public class VolatileDemo {//private volatile static int num = 0;// volatile 不保证原子性//原子类的Integerprivate static  AtomicInteger num = new AtomicInteger();public  static void add(){
//        num++;//不是原子操作num.getAndIncrement();//AtomicInteger+1;(CAS)}public static void main(String[] args) {for(int i=1;i<=20;i++){new Thread(()->{for(int j=0;j<1000;j++){add();}}).start();}while(Thread.activeCount()>2){//两个默认线程在执行gc mainThread.yield();}System.out.println(num);}
}

这些类的底层都是直接和操作系统有关系,在内存中修改值!Unsafe类时一个特殊的存在
3、禁止指令重排
指令重排:
由于内存屏障,volatile可以避免指令重排:
1、保证特定的操作的执行顺序
2、可以保证某些变量的内存可见性(利用volatile的可见性)

深入理解CAS

如果达到期望值,就更新,否则就不更新

 public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(2020);System.out.println(atomicInteger.compareAndSet(2020, 2021));//更新成功或失败trueSystem.out.println(atomicInteger.get());//得到更新后的值2021System.out.println(atomicInteger.compareAndSet(2020, 2022));//falseSystem.out.println(atomicInteger.get());//2021}

CAS:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环(自旋锁)
缺点:
1、循环会耗时
2、一次性只能保证一个共享变量的原子性
3、ABA问题(狸猫换太子)

public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);}

Unsafe类下:

 public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);//获取内存地址中的值} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));//内存操作,提高效率return var5;}

原子引用

原子引用解决ABA问题
ABA问题:

 public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(2020);//期望值达到就更新 否则不更新 CAS是CPU并发的原语//------捣乱的线程System.out.println(atomicInteger.compareAndSet(2020, 2021));System.out.println(atomicInteger.get());//得到更新后的值2021System.out.println(atomicInteger.compareAndSet(2021, 2020));System.out.println(atomicInteger.get());//2021//---期望的线程System.out.println(atomicInteger.compareAndSet(2020, 666));System.out.println(atomicInteger.get());//2021}

java.util.concurrent.atomic.AtomicReference
可以原子更新的对象引用。 有关原子变量属性的描述
public AtomicReference(V initialValue)用给定的初始值创建一个新的AtomicReference。
带版本号的原子操作!
java.util.concurrent.atomic.AtomicStampedReference
Integer使用了对象缓存机制,默认范围为-128~127推荐使用静态工厂方法valueOf获取对象实例,而不是new 因为valueOf使用缓存,而new一定创建新的对象分配新的内存空间
.【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var=?在-128 至 127 之间的赋值,Integer 对象是在
IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行
判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,
推荐使用 equals 方法进行判断
解决ABA问题,引入原子引用,对应的思想是乐观锁

  public static void main(String[] args) {AtomicStampedReference<Integer> atomicStampedReference =  new AtomicStampedReference<Integer>(1,1);new Thread(()->{int stamp = atomicStampedReference.getStamp();//获得版本号System.out.println("a1->"+stamp);try{TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}atomicStampedReference.compareAndSet(1,2,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);System.out.println("a2->"+atomicStampedReference.getStamp());atomicStampedReference.compareAndSet(2,1,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);System.out.println("a3->"+atomicStampedReference.getStamp());}).start();new Thread(()->{int stamp = atomicStampedReference.getStamp();System.out.println("b1->"+stamp);try{TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}atomicStampedReference.compareAndSet(1,2,stamp,stamp+1);System.out.println("b2->"+atomicStampedReference.getStamp());}).start();}

各种锁

1、公平锁、非公平锁
公平锁:非常公平,不能插队(必须先来后到)

 public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}

非公平锁:非常不公平,能插队(默认都是非公平)

 public ReentrantLock() {sync = new NonfairSync();}

2、可重入锁

public class LockDemo {public static void main(String[] args) {Phone phone = new Phone();new Thread(()->{phone.sms();},"A").start();new Thread(()->{phone. sms();},"B").start();}}
class Phone{Lock lock = new ReentrantLock();public void sms(){lock.lock();lock.lock();//Lock锁必须配对,否则就会死在里面try{    System.out.println(Thread.currentThread().getName()+"sms");call();}finally {lock.unlock();lock.unlock();}}public void call(){lock.lock();try{System.out.println(Thread.currentThread().getName()+"call");}finally {lock.unlock();}}
}

自旋锁(CAS):

public class LockDemo2 {AtomicReference atomicReference = new AtomicReference();public void myLock(){Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName()+"->myLock");while(!atomicReference.compareAndSet(null,thread)){}}public void myUnLock(){Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName()+"->myUnLock");atomicReference.compareAndSet(thread,null);}
}
import java.util.concurrent.TimeUnit;public class TestLock {public static void main(String[] args) throws InterruptedException {LockDemo2 lockDemo2 = new LockDemo2();new Thread(()->{lockDemo2.myLock();try{TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}finally {lockDemo2.myUnLock();}},"A").start();TimeUnit.SECONDS.sleep(3);new Thread(()->{lockDemo2.myLock();try{TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}finally {lockDemo2.myUnLock();}},"B").start();}
}
http://www.lbrq.cn/news/2689093.html

相关文章:

  • 网页qq登陆保护网络seo哈尔滨
  • 政府网站建设团队网页生成器
  • 唐山哪个公司做网站如何在百度上推广业务
  • 汽车展示网站微信拓客的最新方法
  • 鲅鱼圈网站在哪做南京谷歌seo
  • 怎么自己做代刷网站网站快速排名优化报价
  • 小程序搭建是什么意思淘宝seo优化怎么做
  • 镇江方圆建设监理咨询有限公司网站对网络营销的认识
  • wordpress 目录权限管理指定关键词排名优化
  • 当地政府网站建设问卷调查自己做一个网站需要什么
  • 二级域名网站建设百度竞价代运营托管
  • 免费帮助建站营销网络是啥意思
  • 佛山网站设计建设网络营销策略概念
  • 网站快速收录软件云搜索网页版入口
  • 做网站帮外国人淘宝crm系统网站
  • 网站推广公司兴田德润在哪里上海最新疫情
  • 做网站服务器和域名2022黄页全国各行业
  • 90做网站整合营销传播名词解释
  • 交互设计师郑州网站建设推广优化
  • 手机网站这么做链接网站关键词如何优化
  • 制作音乐appseo咨询顾问
  • 做网站市场价seo优化主要做什么
  • 淘客类网站如何做排名指数是什么
  • 企业网站对企业有什么好处沙坪坝区优化关键词软件
  • 自己做网站制作教程最近一周新闻热点回顾
  • 网站做记录访客故事式软文范例500字
  • 专业设计网站推荐螺蛳粉营销策划方案
  • 东莞厚街有什么好玩的地方seo实战培训费用
  • 广东品牌女装都有哪些品牌seo关键技术有哪些
  • jsp网站开发实例标题栏江西seo推广方案
  • 三、非线性规划
  • 洛谷 小 Y 拼木棒 贪心
  • 一键生成 Android 适配不同分辨率尺寸的图片
  • 【力扣494】目标和
  • Openlayers基础教程|从前端框架到GIS开发系列课程(24)openlayers结合canva绘制矩形绘制线
  • 数据备份与进程管理