基础学习day11--多线程一线程的创建,运行,同步和锁
一、线程基本概述
1.1、进程和线程
进程:一个应用程序一般都是一个进程,正在进行的程序
每一个进程最少都有一个线程,都有一个执行顺序,该顺序是一个执行路径或者一个控制单元
线程:进程中一个独立的控制单元,线程控制着进程的执行。
windows中的任务管理器,可以查看进程,linux下通过ps命令
线程是进程的最小单位
线程依赖于进程
线程随着进程的创建和创建,随着进程的结束而消亡
如迅雷:可以同时开启多个下载,就是多线程
多个程序同时执行,时CPU在很快的切换,看上去是同时执行,实际上是在CPU在切换执行。
多线程存在的意义:可以让程序中的内容同时执行。
二、继承线程的创建
2.1、继承Thread,重写run方法
package com.pb.thread.demo1; /**
*
* @author Denny
* 继承Thread 类并重写run方法来创建线程类
*
*/
public class MyThread extends Thread { private int count; /*
* 重写run 方法
* @see java.lang.Thread#run()
*/
@Override
public void run(){
/*
* 要运行的代码块或者方法,在这里调用,或者直接写在这里
*/
while(count<10){
count++;
System.out.println("My thread run方法启动了"+count);
}
}
public static void main(String[] args) {
//声明线程类
MyThread mt=new MyThread();
//启动线程,JVM调用run方法
mt.start();
//主线程
for(int x=0;x<10;x++){
System.out.println("main thread"+x);
}
} }
多个线程都在抢占CPU的执行权,谁抢到,谁就执行
在某一时刻,只能有一个程序在运行
CPU在做着快速切换,以达到看上去是同时运行的效果。
多线程一个特性:随机性,谁抢到谁执行.
三、线程的运行和线程状态
3.1、调用start()方法
使该线程开始执行,Java虚拟机调用该线程的run()方法
为什么要重写run方法.
Thread类用于描述线程。
这个类定义一个功能,用于存储线程要运行的代码。该存储功能就是run方法.
也就是说,Thread类中的run方法是用于存储线程要运行的代码
如果直接调用run()方法,就是调用对象的普通方法一样.,仅仅是对象调用方法.线程创建了并没有运行。
只有start()才可以运行线程。
3.2、线程状态
新生:创建线程 new Thread()或者子类
运行:正在运行的线程,调用start()方法
冻结:已经创建的线程,但非运行状态的线程。sleep(long 毫秒), wait()线程等待,直到notify()唤醒才可以继续运行
临时状态阻塞:具备运行资格,但没有执行权,就是还没有被CPU切换到.
消亡:线程死亡stop(),或者线程运行完成。
四、获取线程对象
4.1、获取当前线程对象和名称
继承thread类实现线程,局部变量都有单独的一份不能共享数据
package com.pb.thread.demo1; /**
*
* @author Denny
* 继承Thread 类并重写run方法来创建线程类
*Thread.currentThread(),获取当前线程对象
*继承thread类实现线程,局部变量都有单独的一份不能共享数据
*/
public class MyThread extends Thread { public MyThread(String name){
super(name);
}
/*
* 重写run 方法
* @see java.lang.Thread#run()
*/
@Override
public void run(){
/*
* 要运行的代码块或者方法,在这里调用,或者直接写在这里
*/
for(int x=0;x<10;x++){ System.out.println("My thread run的名字:"+Thread.currentThread().getName()+","+x);
}
}
public static void main(String[] args) {
//声明线程类
MyThread mt1=new MyThread("mt1");
// mt1.setName("张三"); 设置线程名称
MyThread mt2=new MyThread("mt2");
//启动线程,JVM调用run方法
mt1.start();
mt2.start();
//主线程
for(int x=0;x<10;x++){
System.out.println(currentThread().getName()+","+x);
}
} }
示例:
五、接口实现线程
5.1、实现Runnable接口
重写run方法()
实现接口的方式最大的好处是可以共享数据
示例:多窗口同时售票,
package com.pb.thread.demo1; /**
*
* @author Administrator 多个窗口同时卖票
*
*/
public class Ticket implements Runnable { private int tick = 100; public void run() { while (true) {
if (tick > 0) {
System.out.println(Thread.currentThread().getName()+"卖:" + tick--);
}else{
break;
}
}
}
public static void main(String[] args) {
//声明线程类
Ticket ticket=new Ticket();
//创建线程对象,并将类做为参数
Thread t1=new Thread(ticket);
t1.setName("一号窗口,");
Thread t2=new Thread(ticket);
t2.setName("二号窗口,");
Thread t3=new Thread(ticket);
t3.setName("三号窗口,");
Thread t4=new Thread(ticket);
t4.setName("四号窗口,");
t1.start();
t2.start();
t3.start();
t4.start(); } }
结果:
一号窗口,卖:100
一号窗口,卖:98
一号窗口,卖:97
一号窗口,卖:96
一号窗口,卖:95
一号窗口,卖:94
二号窗口,卖:99
二号窗口,卖:92
一号窗口,卖:93
一号窗口,卖:88
一号窗口,卖:87
一号窗口,卖:86
二号窗口,卖:89
二号窗口,卖:84
二号窗口,卖:83
二号窗口,卖:82
二号窗口,卖:81
二号窗口,卖:80
二号窗口,卖:79
二号窗口,卖:78
二号窗口,卖:77
二号窗口,卖:76
二号窗口,卖:75
二号窗口,卖:74
二号窗口,卖:73
二号窗口,卖:72
二号窗口,卖:71
二号窗口,卖:70
二号窗口,卖:69
二号窗口,卖:68
二号窗口,卖:67
二号窗口,卖:66
二号窗口,卖:65
二号窗口,卖:64
二号窗口,卖:63
二号窗口,卖:62
二号窗口,卖:61
二号窗口,卖:60
二号窗口,卖:59
二号窗口,卖:58
二号窗口,卖:57
二号窗口,卖:56
二号窗口,卖:55
二号窗口,卖:54
二号窗口,卖:53
二号窗口,卖:52
二号窗口,卖:51
二号窗口,卖:50
二号窗口,卖:49
二号窗口,卖:48
二号窗口,卖:47
二号窗口,卖:46
二号窗口,卖:45
二号窗口,卖:44
二号窗口,卖:43
二号窗口,卖:42
二号窗口,卖:41
二号窗口,卖:40
二号窗口,卖:39
二号窗口,卖:38
二号窗口,卖:37
二号窗口,卖:36
二号窗口,卖:35
二号窗口,卖:34
二号窗口,卖:33
二号窗口,卖:32
二号窗口,卖:31
二号窗口,卖:30
二号窗口,卖:29
二号窗口,卖:28
二号窗口,卖:27
二号窗口,卖:26
二号窗口,卖:25
二号窗口,卖:24
二号窗口,卖:23
二号窗口,卖:22
二号窗口,卖:21
三号窗口,卖:90
四号窗口,卖:91
三号窗口,卖:19
二号窗口,卖:20
一号窗口,卖:85
二号窗口,卖:16
三号窗口,卖:17
四号窗口,卖:18
三号窗口,卖:13
三号窗口,卖:11
三号窗口,卖:10
三号窗口,卖:9
三号窗口,卖:8
三号窗口,卖:7
三号窗口,卖:6
三号窗口,卖:5
三号窗口,卖:4
三号窗口,卖:3
三号窗口,卖:2
三号窗口,卖:1
二号窗口,卖:14
一号窗口,卖:15
四号窗口,卖:12
两种创建线程方式:
| 优点 | 缺点 | |
| 继承Thread类 |
1.编写简单 2.可以使用this关键字直接访问当前线程 |
无法继承其它类 无法实现数据共享 |
| 实现Runnable接口 |
1.可以继承其它类 2.多个线程之间可以使用同一个Runnable对象 3.可以共享数据 |
编程方式稍微复杂,如需访问当前线程,需要调用Thread类的currentThread()方法 |
六、线程安全
6.1、还是上面的例子
加上sleep(1000)睡觉1秒
package com.day10.thread.demo1;
public class Ticket implements Runnable {
private int num=100;
@Override
public void run() {
while(true){
if(num>0){
try {
Thread.sleep(1000); //当前线程睡觉1秒,毫秒单位
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+",卖出"+num--+"号票");
}
}
}
public static void main(String[] args) {
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
结果:
Picked up JAVA_TOOL_OPTIONS: -javaagent:/usr/share/java/jayatanaag.jar
Thread-0,卖出100号票
Thread-2,卖出99号票
Thread-1,卖出98号票
Thread-3,卖出97号票
Thread-0,卖出96号票
Thread-2,卖出95号票
Thread-1,卖出94号票
Thread-3,卖出93号票
Thread-0,卖出92号票
Thread-2,卖出91号票
Thread-1,卖出90号票
Thread-3,卖出89号票
Thread-0,卖出88号票
Thread-2,卖出87号票
Thread-1,卖出86号票
Thread-3,卖出85号票
Thread-0,卖出84号票
Thread-2,卖出83号票
Thread-1,卖出82号票
Thread-3,卖出81号票
Thread-0,卖出80号票
Thread-2,卖出79号票
Thread-1,卖出78号票
Thread-3,卖出77号票
Thread-0,卖出76号票
Thread-2,卖出75号票
Thread-1,卖出74号票
Thread-3,卖出73号票
Thread-0,卖出72号票
Thread-2,卖出71号票
Thread-1,卖出70号票
Thread-3,卖出69号票
Thread-0,卖出68号票
Thread-2,卖出67号票
Thread-1,卖出66号票
Thread-3,卖出65号票
Thread-0,卖出64号票
Thread-2,卖出63号票
Thread-1,卖出62号票
Thread-3,卖出61号票
Thread-0,卖出60号票
Thread-2,卖出59号票
Thread-1,卖出58号票
Thread-3,卖出57号票
Thread-0,卖出56号票
Thread-2,卖出55号票
Thread-1,卖出54号票
Thread-3,卖出53号票
Thread-0,卖出52号票
Thread-2,卖出51号票
Thread-1,卖出50号票
Thread-3,卖出49号票
Thread-0,卖出48号票
Thread-2,卖出47号票
Thread-1,卖出46号票
Thread-3,卖出45号票
Thread-0,卖出44号票
Thread-2,卖出43号票
Thread-1,卖出42号票
Thread-3,卖出41号票
Thread-0,卖出40号票
Thread-2,卖出39号票
Thread-1,卖出38号票
Thread-3,卖出37号票
Thread-0,卖出36号票
Thread-2,卖出35号票
Thread-1,卖出34号票
Thread-3,卖出33号票
Thread-0,卖出32号票
Thread-2,卖出31号票
Thread-1,卖出30号票
Thread-3,卖出29号票
Thread-0,卖出28号票
Thread-2,卖出27号票
Thread-1,卖出26号票
Thread-3,卖出25号票
Thread-0,卖出24号票
Thread-2,卖出23号票
Thread-1,卖出22号票
Thread-3,卖出21号票
Thread-0,卖出20号票
Thread-2,卖出19号票
Thread-1,卖出18号票
Thread-3,卖出17号票
Thread-0,卖出16号票
Thread-2,卖出15号票
Thread-1,卖出14号票
Thread-3,卖出13号票
Thread-0,卖出12号票
Thread-2,卖出11号票
Thread-1,卖出10号票
Thread-3,卖出9号票
Thread-0,卖出8号票
Thread-2,卖出7号票
Thread-1,卖出6号票
Thread-3,卖出5号票
Thread-0,卖出4号票
Thread-2,卖出3号票
Thread-1,卖出2号票
Thread-3,卖出1号票
Thread-0,卖出0号票
Thread-2,卖出-1号票
Thread-1,卖出-2号票
发现多卖票了,
为什么?因为卖票当前线程睡眠了1秒,其它线程就可以把这张票已经卖出了,
条件检查1>0,如果4个人同时检查,条件成立,就继续卖票就出现了,负数
怎么解决?给线程加锁
1. 多个线程在操作共享的数据。
2. 操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
解决方式:就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算。必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
看下面的同步synchronized
七、同步代码块
7.1、synchronized
同步代码块的格式:
synchronized(对象){
需要被同步的代码;
}
同步的好处:解决了线程的安全问题。
同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
同步的前提:必须有多个线程并使用同一个锁。
修改上面的代码
package com.day10.thread.demo1;
public class Ticket implements Runnable {
private int num=100;
@Override
public void run() {
while(true){
synchronized(this){
if(num>0){
try {
Thread.sleep(1000); //当前线程睡觉1秒,毫秒单位
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+",卖出"+num--+"号票");
}else{
break;
}
}
}
}
public static void main(String[] args) {
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
八、同步函数
8.1、同步方法
package com.day10.thread.demo2;
public class Account {
//余额
private double blance=500;
//取款
public void withDraw(int num){
blance=blance-num;
}
public double getBlance() {
return blance;
}
public void setBlance(double blance) {
this.blance = blance;
}
}
package com.day10.thread.demo2;
public class AccountThread implements Runnable {
private Account account=new Account();
@Override
public void run() {
for (int i = 0; i < 5; i++) {
if(account.getBlance()<0){
System.out.println("透支了!!");
}
makWithDraw(100); //每次取100
}
}
/*
* 取款的方法
*/
public void makWithDraw(int num){
//判断余额是不是大于要取款的数
if(account.getBlance()>=num){
System.out.println(Thread.currentThread().getName()+":准备取款!");
try {
Thread.sleep(1000); //等待1秒
account.withDraw(num);
System.out.println(Thread.currentThread().getName()+":取款完成!,当前余额为:"+account.getBlance());
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println(Thread.currentThread().getName()+" 余额不足以支付当前取款, 余额为: "+account.getBlance());
}
}
}
package com.day10.thread.demo2;
public class Demo {
public static void main(String[] args) {
AccountThread at=new AccountThread();
Thread t1=new Thread(at);
t1.setName("张三");
Thread t2=new Thread(at);
t2.setName("张三老婆");
t1.start();
t2.start();
}
}
结果:
张三:准备取款!
张三老婆:准备取款!
张三:取款完成!,当前余额为:400.0
张三:准备取款!
张三老婆:取款完成!,当前余额为:300.0
张三老婆:准备取款!
张三:取款完成!,当前余额为:200.0
张三:准备取款!
张三老婆:取款完成!,当前余额为:100.0
张三老婆:准备取款!
张三:取款完成!,当前余额为:0.0
张三 余额不足以支付当前取款, 余额为: 0.0
张三 余额不足以支付当前取款, 余额为: 0.0
张三老婆:取款完成!,当前余额为:-100.0
透支了!!
张三老婆 余额不足以支付当前取款, 余额为: -100.0
透支了!!
张三老婆 余额不足以支付当前取款, 余额为: -100.0
加上同步关键字
/*
* 取款的方法
*/
public synchronized void makWithDraw(int num){
//判断余额是不是大于要取款的数
if(account.getBlance()>=num){
System.out.println(Thread.currentThread().getName()+":准备取款!");
try {
Thread.sleep(1000); //等待1秒
account.withDraw(num);
System.out.println(Thread.currentThread().getName()+":取款完成!,当前余额为:"+account.getBlance());
} catch (InterruptedException e) {
e.printStackTrace();
} }else{
System.out.println(Thread.currentThread().getName()+" 余额不足以支付当前取款, 余额为: "+account.getBlance());
}
}
结果:
张三:准备取款!
张三:取款完成!,当前余额为:400.0
张三老婆:准备取款!
张三老婆:取款完成!,当前余额为:300.0
张三:准备取款!
张三:取款完成!,当前余额为:200.0
张三:准备取款!
张三:取款完成!,当前余额为:100.0
张三:准备取款!
张三:取款完成!,当前余额为:0.0
张三 余额不足以支付当前取款, 余额为: 0.0
张三老婆 余额不足以支付当前取款, 余额为: 0.0
张三老婆 余额不足以支付当前取款, 余额为: 0.0
张三老婆 余额不足以支付当前取款, 余额为: 0.0
张三老婆 余额不足以支付当前取款, 余额为: 0.0
没有发生透支现象
同步代码块:
/*
* 取款的方法
*/
public void makWithDraw(int num){
synchronized(account){
//判断余额是不是大于要取款的数
if(account.getBlance()>=num){
System.out.println(Thread.currentThread().getName()+":准备取款!");
try {
Thread.sleep(1000); //等待1秒
account.withDraw(num);
System.out.println(Thread.currentThread().getName()+":取款完成!,当前余额为:"+account.getBlance());
} catch (InterruptedException e) {
e.printStackTrace();
} }else{
System.out.println(Thread.currentThread().getName()+" 余额不足以支付当前取款, 余额为: "+account.getBlance());
}
}
}
结果同上,没有发生透支现象
1. 同步函数的锁是固定的this。
2. 同步代码块的锁是任意的对象。
建议使用同步代码块。
九、同步锁
9.1、同锁
同步方法同步对象是this,同步代码块也可以使用this来同步
十、静态同步
10.1、静态同步
不是this,因为静态方法中也不可以定义this
静态进内存,内存中没有本类对象,但是一定有该类对应的字节码文件对象
静态的同步函数使用的锁是该函数所属字节码文件对象,可以用getClass方法获取,也可以用当前类名.class表示。
synchronizid(类名.class){ 或者对象.getClass
}
十一、单例模式加上同步懒汉式
11.1、懒汉式加锁
package com.day10.thread.demo2;
/**
*
* @author denny
*单例模式
*饿汉式,不存在复生成对象的问题
*懒汉工,加synchronize
*/
public class SingleDemo {
private static SingleDemo singleDemo; private SingleDemo(){ }
public static SingleDemo getNewIntance(){
if(singleDemo==null){//判断是不是空,不是空就直接返回,是空就加锁
synchronized(SingleDemo.class){ //加锁 //this.getClass() 直接写对象singleDemo.getClass()也行 if(singleDemo==null){
singleDemo=new SingleDemo();
}
}
}
return singleDemo; } }
十二、死锁
12.1、死锁常见情景之一:同步的嵌套。
class MyLock{
static Object lockA=new Object();
static Object lockB=new Object();
}
public class Demo implements Runnable {
private boolean flag;
public Demo(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
while (true) {
synchronized (MyLock.lockA) {
System.out.println("if.........lockA");
synchronized (MyLock.lockB) {
System.out.println("if.........lockB");
}
}
}
}
else {
while(true){
synchronized (MyLock.lockB) {
System.out.println("else.........lockB");
synchronized (MyLock.lockA) {
System.out.println("else.........lockA");
}
}
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Demo(true));
Thread t2 = new Thread(new Demo(false));
t1.start();
t2.start();
}
}
建议将要锁的对象,声明为static
基础学习day11--多线程一线程的创建,运行,同步和锁的更多相关文章
- Java多线程之线程的创建
好久没有更博客了,最近一直在忙工作的事情.现在终于空下来了,这2天会抓紧时间整理多线程和socket,把JavaSE结束掉. 关于多线程,首先会涉及到哪些东西呢?首先要了解线程,为什么要使用线程,线程 ...
- C/C++ Muti-Thread多线程编程学习(之)线程Thread | 创建、运行、结束
文章目录 前言 线程 Thread 创建线程 CreateThread _beginthread _beginthreadex pthread_create 线程运行 结束线程 前言 多线程(Mu ...
- Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)
线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...
- Linux多线程编程——线程的创建与退出
POSIX线程标准:该标准定义了创建和操纵线程的一整套API.在类Unix操作系统(Unix.Linux.Mac OS X等)中,都使用Pthreads作为操作系统的线程.Windows操作系统也有其 ...
- .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法
1.多线程简单使用(1)进程是不执行代码的,执行代码的是线程,一个进程默认有一个线程(2)线程默认情况下都是前台线程,要所有的前台线程退出以后程序才会退出,进程里默认的线程我们叫做主线程或者叫做UI线 ...
- 黑马程序员——JAVA基础之简述多线程,两种创建多线程的方式
------- android培训.java培训.期待与您交流! ---------- 多线程: 进程和线程: 进程:是一个正在执行中的程序.每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者 ...
- Java并发学习之中的一个——线程的创建
本文是学习网络上的文章时的总结,感谢大家无私的分享. 1.与每一个Java语言中的元素一样,线程是对象.在Java中,我们有两种方式创建线程: a.通过直接继承thread类,然后覆盖run方法. b ...
- java学习笔记 --- 多线程(线程安全问题——同步代码块)
1.导致出现安全问题的原因: A:是否是多线程环境 B:是否有共享数据 C:是否有多条语句操作共享数据 2.解决线程安全问题方法: 同步代码块: synchronized(对象){ 需要同步的代码; ...
- (C#- 多线程) 在线程中创建object,共享问题。
研究如下问题: 1. 在一个进程的主线程中创建一个Object,其他线程都可以访问这个Object,并操作Object的方法. - 多线程同步问题. 2. 在一个进程的多个线程里面,每个线程都创建同一 ...
- 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题
调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...
随机推荐
- 正确理解静态Static关键字
与其他语言不通,C#没有全局变量和全局函数的感念,C#的所有字段和方法都出现在一个类的上下文中,在C#中与全局字段或函数等价的就是静态字段或方法.“全局字段或方法”与“C#的静态字段或方法”没有功能上 ...
- STL中的map/multimap小结
(1)使用map/multimap之前必须包含头文件<map>:#include<map> 并且和所有的关联式容器一样,map/multimap通常以平衡二叉树来完成 (2)n ...
- Sass学习之路:Sass、Compass安装与命令行
导言 CSS不是一门真正意义上的编程语言,很多编程语言理所当然的特性(比如变量),都不被支持.同时再开发模块化的web项目的时候,也要避免相互干扰.为了弥补CSS的这些不足,就产生了CSS预处理器,S ...
- Tip8:Unity中诸如 Awake() Start() Update()等函数的 执行顺序
Unity脚本中有很多的事件函数,下面是各种函数的执行顺序: 1.reset(); 2.Awake(); 3.OnEnable; 4.OnLevelWasLoaded(); 5.Start(); 6. ...
- 15套精美的免费界面设计 PSD 素材【免费下载】
在这个集合中,我们聚集15套精美的 PSD 界面设计模板,网页元素,用户界面工具包,扁平化图标,APP 应用程序 UI 设计的等等.这些来自优秀设计师的 PSD 源文件素材让其它的设计师们在设计用 ...
- 美了美了!22款精美的 iOS 应用程序图标模板
22款制作精美的 iOS 应用程序图标设计作品,遵循图形设计的现代潮流,所有图标都非常了不起,给人惊喜.通过学习这些移动应用程序图标,设计人员可以提高他们的创作,使移动用户界面看起来更有趣和吸引人. ...
- iOS-金额小写转大写
一.目的 1. 金额小写转化成大写. 如 123456.65 --> 壹拾贰万叁仟肆佰伍拾陆元陆角伍分 2. 只能处理13位数的金额,并且只能处理到小数点后两位. 二.代码 #import &q ...
- 说说jsonp
什么是jsonp jsonp充其量只能说是一种"方法".它可以让页面从其他域中获取资料. 首先要知道的是同源策略,在javascript中使用http请求(ajax)是会受到同 ...
- spring事务与消息队列
在开发过程中,遇到一个bug,产生bug的原因是spring事务提交晚于消息队列的生产消息,导致消息队列消费消息时获取到的数据不正确.这篇文章介绍问题的产生和一步步的解决过程. 一.问题的产生: 场景 ...
- .net core 1.0 Web MVC 自定义认证过程
通过官方的介绍可知,若要本地开始部署搭建一个基于.net core 1.0的Web应用,需要下载dotnet SDK,或在Visual Studio IDE之上安装相关插件以布置开发环境.为了使开发环 ...