一、进程与线程

1.1、进程

进程是应用程序的执行实例。

进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程
特征:
动态产生,动态消亡。
进程是并发性的。
进程独立性。是一个独立运行的基本单位,也是系统分配资源和调度的基本单位

1.2、线程

多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位
线程:进程内部的一个执行单元,它是程序中一个单一的顺序控制流程
特点:
  • 线程依赖进程生存
  • 一个进程可以包含多个线程,而一个线程至少要有一个父进程
  • 线程可以有自己的堆栈,程序计数器和局部变量。
  • 线程与父进程的其他线程共享进程所有的全部资源
  • 线程是独立运行,采用抢占方式。
  • 一个线程可以创建和删除别外一具线程
  • 同一个进程中的多个线程之间可以并发执行
  • 线程的调试管理是由进程来完成的。
  • 原则:编程时,必须确保线程不会妨碍同一进程的其他线程

1.3、线程分类

  • 系统级线程:又称核心级线程,负责管理调度不同进程之间的多个线程,由操作系统直接管理
  • 用户级线程:仅存于用户空间,在应用 程序中控制其创建,执行和消亡

1.4、多线程优势

  • 改善用户体验
  • 提高资源的利用率

二、Java中线程的实现

  • 一种是继承Thread类
  • 另一种就是实现Runnable接口

使用步骤:

定义一个线程----创建线程的实例--启动线程--终止线程

2.1、继承Thread类

Thread类是在java.lang包中定义的,一个类只要继承了Thread类,此类就称为多线程操作类。在Thread子类之中,必须明确的覆写Thread类中的run()方法,此方法为线程的主体
/**
* 继承Thread类重写run方法
*
*/
public class MyThead1 extends Thread {
private int count; @Override
public void run() {
System.out.println("=======线程启动了=======");
while(this.count<100){
count++; }
System.out.println("count最终的值:"+count);
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} }

测试类

/**
* 测试类
* MyTheadDemo
* 继承Thread类创建线程
* 1.继承Thread类
* 2.重写run方法
* 3.实例化线程类对象
* 4.调用start方法启动线程
*
* 继承Thread类存在问题
* Java中是单继承的,线程类不能继承其它的类
*
* 解决办法:实现Runnable接口
*
*/
public class MyTheadDemo1 { public static void main(String[] args) {
//实例化线程类对象
MyThead1 myThead1=new MyThead1();
//启动线程
myThead1.start();
/*
* start方法的作用
* 该方法公使操作系统初始化一个新的线程
* 由这个新线程来执行线程对象的Run方法
*/ } }

2.2、实现Runnable接口(推荐使用,使用接口可以解决Java中单继承的问题)

在Java中也可以通过实现Runnable接口的方式实现多线程,Runnable接口中只定义了一个抽象方法:
public void run() ;
 
 
/**
* 实现Runnable接口
*
*/
public class MyRunnable implements Runnable {
private int count; @Override
public void run() {
System.out.println("=======线程启动了=======");
while(this.count<100){
count++; }
System.out.println("count最终的值:"+count);
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} }

测试类

/**
* 测试类
* MyRunnable
* 实现Runnable接口创建线程
* 1.实现Runnable接口
* 2.实现run方法
* 3.实例化线程类对象
* 4.创建Thread类实例对象,并将实例化的线程对象传入
* 5.调用Thread类实例对象的start方法启动线程
*
*/
public class MyRunnableDemo { public static void main(String[] args) {
//实例化线程类对象
Runnable myRunnable=new MyRunnable();
Thread thread=new Thread(myRunnable);
//或者Thread thread=new Thread(new MyRunnable());
//启动线程
thread.start(); } }

2.3、启动线程

  • 继承Thread类启动线程方法:

如果要想正确的启动线程,是不能直接调用run()方法的,应该调用从Thread类中继承而来的start()方法,才可以启动线程

  • 实现Runnable接口启动线程方法:
实际上此时,还是要依靠Thread类完成启动,在Thread类中提供了以下的两个构造方法:
public Thread(Runnable target)
public Thread(Runnable target,String name)
 

2.4、Thread类和Runnable接口的区别

Thread类和Runnable接口之间在使用上也是有所区别的,如果一个类继承Thread类,则不适合于多个线程共享资源,而实现了Runnable接口,则可以方便的实现资源的共享。

/**
* 实现Runnable接口
*
*/
public class MyRunnable implements Runnable {
private int count; @Override
public void run() {
count++; System.out.println("count最终的值:"+count);
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} }

测试类

/**
* 测试类
* MyRunnable
* 实现Runnable接口创建线程
* 1.实现Runnable接口
* 2.实现run方法
* 3.实例化线程类对象
* 4.创建Thread类实例对象,并将实例化的线程对象传入
* 5.调用Thread类实例对象的start方法启动线程
*
*/
public class MyRunnableDemo { public static void main(String[] args) {
//实例化线程类对象
Runnable myRunnable=new MyRunnable();
Thread thread=new Thread(myRunnable);
Thread thread2=new Thread(myRunnable);
//或者Thread thread=new Thread(new MyRunnable());
//启动线程
System.out.println("线程1启动");
thread.start(); System.out.println("线程2启动");
thread2.start(); } }

结果:

线程1启动
线程2启动
count最终的值:1
count最终的值:2

再看下thread方式

/**
* 继承Thread类重写run方法
*
*/
public class MyThead1 extends Thread {
private int count; @Override
public void run() { count++;
System.out.println("count最终的值:"+count);
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} }
/**
* 测试类
* MyTheadDemo
* 实现Runnable接口创建纯种
* 1.实现Runnable接口
* 2.重写run方法
* 3.实例化线程类对象
* 4.调用start方法启动线程
*
* 继承Thread类存在问题
* Java中是单继承的,线程类不能继承其它的类
*
* 解决办法:实现Runnable接口
*
*/
public class MyTheadDemo1 { public static void main(String[] args) {
//实例化线程类对象
MyThead1 myThead1=new MyThead1();
MyThead1 myThead2=new MyThead1();
//启动线程
System.out.println("线程1启动");
myThead1.start();
System.out.println("线程2启动");
myThead2.start();
/*
* start方法的作用
* 该方法公使操作系统初始化一个新的线程
* 由这个新线程来执行线程对象的Run方法
*/ } }

结果:

线程1启动
线程2启动
count最终的值:1
count最终的值:1

三、线程的状态

要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有五种状态,即创建、就绪、运行、阻塞、终止。
 
 
 

四、线程的优先级和方法

4.1、线程的优先级

  • 默认情况下,一个线程继承其父类的优先级
  • 优先级表示为一个整数值
  • 优先级越高,执行的机会越大,反之,执行的机会就越小
  • 高优先级的线程可以抢占低优先级线程的CPU资源
  • 线程的优先级与线程执行的效率没有必然的联系

4.2、线程的方法

No.
方法名称
类型
描述
1
public Thread(Runnable target)
构造
接收Runnable接口子类对象,实例化Thread对象
2
public Thread(Runnable target,String name)
构造
接收Runnable接口子类对象,实例化Thread对象,并设置线程名称
3
public Thread(String name)
构造
实例化Thread对象,并设置线程名称
4
public static Thread currentThread()
普通
返回目前正在执行的线程
5
public final String getName()
普通
返回线程的名称
6
public final int getPriority()
普通
发挥线程的优先级
7
public boolean isInterrupted()
普通
判断目前线程是否被中断,如果是,返回true,否则返回false
8
public final boolean isAlive()
普通
判断线程是否在活动,如果是,返回true,否则返回false
9
public final void join() throws InterruptedException
普通
等待线程死亡
10
public final synchronized void join(long millis) throws InterruptedException
普通
等待millis毫秒后,线程死亡
11
public void run()
普通
执行线程
12
public final void setName(String name)
普通
设定线程名称
13
public final void setPriority(int newPriority)
普通
设定线程的优先值
14
public static void sleep(long millis) throws InterruptedException
普通
使目前正在执行的线程休眠millis毫秒
15
public void start()
普通
开始执行线程
16
public static void yield()
普通
将目前正在执行的线程暂停,允许其它线程执行
17
public final void setDaemon(boolean on)
普通
将一个线程设置成后台运行
18
public final void setPriority(int newPriority)
普通
更改线程的优先级

五、线程调度

5.1、join()方法

作用:阻塞指定的线程等到另一个线程完成以后,再继续执行

package thead;
/**
* 实现join方法
* 1.join的线程运行完成后,才会继承运行当前线程
* 2.join之前要先启动线程start方法
*
*/
public class JoinRunnable implements Runnable { @Override
public void run() {
for (int i = 0; i <5; i++) {
System.out.println(Thread.currentThread().getName()+" 第"+i+"次");
} } public static void main(String[] args) {
//主线程
for (int i = 0; i <10; i++) {
if(i==5){
Thread thread=new Thread(new JoinRunnable());;
thread.setName("半路切入的线程:");
try {
//启动线程
thread.start();
//半路加入线程
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" 第"+i+"次");
}
} }

结果:

main   第0次
main 第1次
main 第2次
main 第3次
main 第4次
半路切入的线程: 第0次
半路切入的线程: 第1次
半路切入的线程: 第2次
半路切入的线程: 第3次
半路切入的线程: 第4次
main 第5次
main 第6次
main 第7次
main 第8次
main 第9次

5.2、sleep()

阻塞当前线程,当前等待的线程将获得机会

调用sleep方法后,,当前线程会被扶起(暂停执行)当前线程会释放资源

package thead;

public class SleepRunnable implements Runnable {

    @Override
public void run() {
try {
for (int i = 0; i < 10; i++) { //每一秒执行一次
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} } public static void main(String[] args) {
Thread sleepThread=new Thread(new SleepRunnable());
sleepThread.setName("等待中的线程");
sleepThread.start();
for (int i = 0; i < 10; i++) {
if(i==5){
try {
//主线程=等5秒
Thread.sleep(5000); } catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+i);
} } }

结果:

main0
main1
main2
main3
main4
等待中的线程0
等待中的线程1
等待中的线程2
等待中的线程3
main5
main6
main7
main8
main9
等待中的线程4
等待中的线程5
等待中的线程6
等待中的线程7
等待中的线程8
等待中的线程9

5.3、yield()方法

将当前线程转入可运行状态,

package yield;
/**
* 线程一
*
*/
public class MyThread1 implements Runnable { @Override
public void run() {
for (int i = 0; i <10; i++) {
Thread.yield();
System.out.println(Thread.currentThread().getName()+":"+i);
} } } package yield;
/**
* 线程二
*
*/
public class MyThread2 implements Runnable { @Override
public void run() {
for (int i = 0; i <10; i++) {
Thread.yield();
System.out.println(Thread.currentThread().getName()+": "+i);
} } } package yield;
/**
* yield方法使用
*2个线程抢占方式
*/
public class Test { public static void main(String[] args) {
Thread myThread1=new Thread(new MyThread1());
myThread1.setName("线程1");
Thread myThread2=new Thread(new MyThread2());
myThread2.setName("线程2");
//同时启动2个线程
myThread1.start();
myThread2.start();
} }

结果:

线程2: 0
线程1:0
线程2: 1
线程1:1
线程2: 2
线程1:2
线程2: 3
线程1:3
线程1:4
线程2: 4
线程1:5
线程1:6
线程1:7
线程1:8
线程1:9
线程2: 5
线程2: 6
线程2: 7
线程2: 8
线程2: 9

 sleep()和yield()方法比较

  • sleep()方法使当前线程转入被阻塞的状态,而yield()方法使用当前线程转入可运行状态
  • sleep()方法总是强制当前线程停止执行,百yield() 方法不一定
  • sleep()方法可以使其它等待运行的线程有同样的执行级别而yield()方法只使相同或者更高优先级的线程获得执行机会
  • 使用sleep()方法时需要捕获异常,而yield()方法无需要捕获异常

5.4、setDaemon()方法

将线程设置 为后台线程(守护线程)。

只能在线程启动之前设置.

package thead;

public class Daemon implements Runnable {

    @Override
public void run() {
for (int i = 0; i <10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
} } public static void main(String[] args) {
Thread daemon=new Thread(new Daemon());
daemon.setName("后台线程");
// 设置为后台线程
daemon.setDaemon(true);
daemon.start();
for (int i = 0; i <10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
} } }

六、同步

一个多线程的程序,如果是通过Runnable接口实现的,则意味着类中的属性将被多个线程共享,那么这样一来就会造成一种问题,如果这多个线程要操作同一资源的时候就有可能出现资源的同步问题。例如:以之前的卖票程序来讲,如果多个线程同时操作的时候就有可能出现卖出票为负数的问题。
问题的解决
如果想解决这样的问题,就必须使用同步,所谓的同步就是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行
解决资源共享的同步操作,可以使用同步代码块和同步方法两种方式完成
同步代码块
在代码块上加上“synchronized”关键字的话,则此代码块就称为同步代码块。
同步方法
除了可以将需要的代码设置成同步代码块之外,也可以使用synchronized关键字将一个方法声明成同步方法。
同步方法定义格式:
synchronized 方法返回值 方法名称(参数列表){}

6.1、简单例子

同一账户2个人同时取款

package demo;

public class Account {

    //余额
private int balance=500;
//检查余额 public int getBalance() {
return balance;
} //取款
public void withDraw(int amount){
balance=balance-amount;
} public void setBalance(int balance) {
this.balance = balance;
} } package demo; public class TestAccount implements Runnable{
private Account account=new Account(); @Override
public void run() {
for (int i = 0; i <5; i++) {
//一次取走100
makeWithDraw(100);
if(account.getBalance()<0){
System.out.println("账户透支了!!!!!");
} } }
//取款参数 同步方法
private synchronized void makeWithDraw(int amount){
if(account.getBalance()>=amount){
//当前余额是否足够可以取款
System.out.println(Thread.currentThread().getName()+" 准备取款");
try {
//0.5秒后取款
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//完成取款
account.withDraw(amount);
System.out.println(Thread.currentThread().getName()+" 完成取款,当前余额为: "+account.getBalance()); }else{
//如果余额不足不能取款
System.out.println(Thread.currentThread().getName()+" 余额不足以支付当前取款, 余额为: "
+account.getBalance());
}
} }

测试类

package demo;
/**
* 如果一个资源被多个线程使用,不上锁就会造成读取严重错误
* 如果想让当前资源被一个线程使用时,不会受到其他纯种的影响,应该给当前资源上锁
* Java中使用sychronized关键字保证数据同步
*
*/
public class Test { public static void main(String[] args) {
//创建线程类的实例
TestAccount ta=new TestAccount();
//创建线程
Thread thread1=new Thread(ta);
thread1.setName("张三");
Thread thread2=new Thread(ta);
thread2.setName("张三的妻子");
//启动线程
thread1.start();
thread2.start();
} }

上面是同步方法

下面是同步代码块

package demo;

public class TestAccount implements Runnable{
private Account account=new Account(); @Override
public void run() {
for (int i = 0; i <5; i++) {
//一次取走100
makeWithDraw(100);
if(account.getBalance()<0){
System.out.println("账户透支了!!!!!");
} } }
//取款参数
private void makeWithDraw(int amount){
//同步代码块
synchronized (account){
if(account.getBalance()>=amount){
//当前余额是否足够可以取款
System.out.println(Thread.currentThread().getName()+" 准备取款");
try {
//0.5秒后取款
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//完成取款
account.withDraw(amount);
System.out.println(Thread.currentThread().getName()+" 完成取款,当前余额为: "+account.getBalance()); }else{
//如果余额不足不能取款
System.out.println(Thread.currentThread().getName()+" 余额不足以支付当前取款, 余额为: "
+account.getBalance());
}
}
} }

七、线程间通信的实现

  • wait()方法:
  • notify()方法:
  • notifyAll()方法:

以上3个方法只能在同步方式或者同步代码块中使用

wait()方法:会挂起当前的线程,并且释放共享资源的锁。当前线程会从可运行状态转为阻塞状态直到调用了wait()方法所属的那个对象的notify()方法或者notifyAll()方法.

notify()方法:可以唤醒因为调用wait()方法而被挂起的那个线程,并且使这个线程退出阻塞状态进入可运行状态

notifyAll()方法:可以唤醒因为所有调用wait()方法而被挂起的那个线程,并且使这些线程退出阻塞状态进入可运行状态

生产者和消费者

package com.pb;
/**
* 商品共享数据
*
*/
public class SharedData { private char c;
private boolean idProducted=false;//信号量
//同步方法生产者生产产品的的方法
public synchronized void putSharedChar(char c){
//如果产品还没有被消费,则生产都等待
if(idProducted){
try {
System.out.println("消费者还未消费,因此生产都停止生产");
wait();
} catch (InterruptedException e) { e.printStackTrace();
}
}
this.c=c;
idProducted=true; //标记已经生产
notify();//通知消费都
System.out.println("生产者生产了产品"+c+",通知消费者");
}
//同步方法 消费者消费产品的的方法
public synchronized char getSharedChar(char c){
//如果产品还没有被消费,则生产都等待
if(idProducted==false){
try {
System.out.println("生产者还未生产,消费者停止消费");
wait();
} catch (InterruptedException e) { e.printStackTrace();
}
} idProducted=false; //标记已经消费
notify();//通知生产者
System.out.println("消费者消费了产品"+c+",通知生产者");
return this.c; }
}
package com.pb;
/**
* 生产者
*
*/
public class Producer implements Runnable {
//共享数据
private SharedData sharedData; public Producer(SharedData sharedData){
this.sharedData=sharedData;
} @Override
public void run() {
for (char c = 'A'; c <= 'D'; c++) { try {
Thread.sleep((int)Math.random()*3000); } catch (InterruptedException e) { e.printStackTrace();
}
//将产品生产后,放入仓库
sharedData.putSharedChar(c);
} } }
package com.pb;
/**
* 消费者
*
*/
public class Consumer implements Runnable {
//共享数据
private SharedData sharedData; public Consumer(SharedData sharedData){
this.sharedData=sharedData;
}
@Override
public void run() {
char ch = 0;
do {
try {
Thread.sleep((int)Math.random()*3000); } catch (InterruptedException e) { e.printStackTrace();
}
//从仓库中取中产品
ch=sharedData.getSharedChar(ch);
} while (ch!='D'); } }

测试类

package com.pb;

public class CommunicationDemo {

    public static void main(String[] args) {
//共享资源,产品
SharedData sharedData=new SharedData();
Thread producer=new Thread(new Producer(sharedData));
Thread consumer=new Thread(new Consumer(sharedData)); //启动线程
consumer.start();
producer.start(); } }

结果:

生产者还未生产,消费者停止消费
生产者生产了产品A,通知消费者
消费者消费了产品A,通知生产者
生产者生产了产品B,通知消费者
生产者还未生产,消费者停止消费
生产者生产了产品C,通知消费者
消费者消费了产品B,通知生产者
生产者生产了产品D,通知消费者
消费者消费了产品C,通知生产者
 
 

Java从零开始学四十四(多线程)的更多相关文章

  1. Java从零开始学二十四(集合工具类Collections)

    一.Collections简介 在集合的应用开发中,集合的若干接口和若干个子类是最最常使用的,但是在JDK中提供了一种集合操作的工具类 —— Collections,可以直接通过此类方便的操作集合 二 ...

  2. 从零开始学安全(十四)●Windows Server 2012 R2 本地搭建FTP服务器

    打开仪表盘添加角色和功能向导 下一步 等待安装完成 打开iis 新建站点 点击 选一个目录作为 ftp文件服务器的存储路径 后面就和iis 创建站点一样了 匿名就不需要密码 就可以访问基本需要特定的账 ...

  3. Java从零开始学三十九(对象序列化)

    一.序列化 将对象的状态存储到特定存储介质中的过程 对象序列化,就是把一个对象变为二进制的数据流的一种方法,通过对象序列化可以方便的实现对象的传输或存储.   序列化保存对象的“全景图”,构建对象的“ ...

  4. Java从零开始学三十三四(JAVA IO-流简述)

    一.流概念(stream) File类并不能对文件内容进行读写. 读文件就是指:把文件的内中的数据读取到内存中来 写文件就是指:把内存中的数据写入到文件中去. 通过什么读写文件呢?文件流. 1.1.流 ...

  5. Java从零开始学三十二(正则表达式)

    一.为什么要有正则 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆份.替换功能. 例如:现在要求判断一个字符串是否由数字组成,则可以有以下的两种做法: 不使用正则完成 使用正则完 ...

  6. Java从零开始学三十(String和StringBuffer类)

    一.StringBuffer连接字符操作 当一个字符串的内容需要被经常改变时就要使用StringBuffer 在StringBuffer中使用append()方法,完成字符串的连接操作   二.Str ...

  7. Java从零开始学二十二(集合Set接口)

    一.Set接口的定义 Set接口也是Collection接口的子接口,但是与Collection或List接口不同的是,Set接口中不能加入重复的元素 Set接口的主要方法与Collection是一致 ...

  8. Java从零开始学二十(集合简介)

    一.为什么需要集合框架 数组的长度是固定的,但是如果写程序时并不知道程序运行时会需要多少对象.或者需要更复杂的方式存储对象,---那么,可以使用JAVA集合框架,来解决这类问题 二.集合框架主要接口 ...

  9. Java从零开始学三十八(JAVA IO- 重定向IO)

    一.三个静态变量 java.lang.System提供了三个静态变量 System.in(默认键盘) System.out(默认显示器) System.err 二.重写向方法 System提供了三个重 ...

  10. Java从零开始学三十六(JAVA IO- 字符流)

    一.字符流 BufferedReader:BufferedReader是从缓冲区之中读取内容,所有的输入的字节数据都将放在缓冲区之中 BufferedWriter:把一批数据写入到缓冲区,当缓冲区区的 ...

随机推荐

  1. Bower 手册

    安装 Bower 使用 npm 安装 Bower.(Bower 依赖于 Node, npm 和 Git.) $ npm install -g bower 基本用法 安装程序包 程序包安装命令 bowe ...

  2. Logcat 不显示日志的另一个原因. 跟cocos2dx关系不大.

    在Android真机调试时,如果在eclipse中看不到LogCat信息,提示是: $ adb logcat info: log device is empty! 原因是系统默认关闭了log,需要将其 ...

  3. Asp.net Mvc4 基于Authorize实现的模块权限验证方式

    在MVC中,我们可以通过在action或者controller上设置Authorize[Role="xxx"] 的方式来设置用户对action的访问权限.显然,这样并不能满足我们的 ...

  4. SQL Server里的自旋锁介绍

    在上一篇文章里我讨论了SQL Server里的闩锁.在文章的最后我给你简单介绍了下自旋锁(Spinlock).基于那个基础,今天我会继续讨论SQL Server中的自旋锁,还有给你展示下如何对它们进行 ...

  5. HTML简明教程(二)

    HTML简明教程(二) 一.HTML 图像 二.HTML 表格 三.HTML 列表 四.HTML div和 span 五.HTML 布局 六.HTML 表单和输入 七.HTML 框架 八.HTML内联 ...

  6. css知识

    margin和padding是什么意思 margin外边距,padding内边距,外边距表示一个元素的边到相邻元素的距离,内边距表示元素之间的内容和元素边框的距离. font:12px/1.5 表示什 ...

  7. 继续谈论XSS

    这篇文章基于上篇谈论XSS ,想说下自己工作过程中遇到的xss的问题. 易出现XSS的场景 1 jsonp 说说jsonp 中也有说过,jsonp其实是很容易出现安全问题的.由于jsonp的callb ...

  8. 《精通Linux内核必会的75个绝技》知识杂记

    http://www.ibm.com/developerworks/cn/linux/l-cn-utrace/ utrace是为运行态的进程提供trace和debug支持. utrace能做如下事情: ...

  9. spring事务与消息队列

    在开发过程中,遇到一个bug,产生bug的原因是spring事务提交晚于消息队列的生产消息,导致消息队列消费消息时获取到的数据不正确.这篇文章介绍问题的产生和一步步的解决过程. 一.问题的产生: 场景 ...

  10. C#类的一些概念

    一.概念 1.类的作用是来模拟现实对象的,一个现实对象可以从两个地方进行描述:特征和行为. 2.类不是你凭空想象的,它只是描述现实对象具体的特征和行为的. 3我们写类只需要写我们所需要的. 4.类是提 ...